亲宝软件园·资讯

展开

Spring源码--debug分析循环依赖--构造器注入

chris_lou_yang 人气:0

目的:源码调试构造器注入,看看是怎么报错的。

spring:5.2.3

jdk:1.8

一、准备

  首先准备两个循环依赖的类:userService和roleServic

<bean id="userService" class="com.chris.spring.service.UserServiceImpl">
    <constructor-arg ref="roleService"/>
</bean>
<bean id="roleService" class="com.chris.spring.service.RoleService">
   <constructor-arg ref="userService"/>
</bean>

二、开始调试

  因为依赖注入的触发点是容器初始化所有非懒加载Bean时候,所以可以直接refresh()方法中的finishBeanFactoryInitialization(beanFactory);方法看起。

 1     /**
 2      * Finish the initialization of this context's bean factory,
 3      * initializing all remaining singleton beans.
 4      */
 5     protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
       ......
       //初始化所有非懒加载的单例bean, 32 // Instantiate all remaining (non-lazy-init) singletons. 33 beanFactory.preInstantiateSingletons(); 34

1.获取BeanDefinition集合


 说明:可以看到userService和roleServic已经在容器中,准备初始化了。继续:

2. 判断是否需要实例化

  1.  循环遍历每个BeanDefinition,判读是不是  非抽象的&&单例的&&懒加载的  bean,不是跳过。
  2. 判断是不是工厂bean,是工厂bean,走处理工厂的方法。
  3. 不是工厂bean,是普通bean,初始化,继续向下

 

 

getSingleton(beanName);作用:从缓存中获取单例Bean。

 

 

 singletonObjects用于缓存单例对象。从singletonObjects获取userService。由于是第一次获取,里面肯定没有。

 

 

 调用isSingletonCurrentlyInCreation(beanName)方法,判断是不是在初始化中:

 

 

 singletonsCurrentlyInCreation用于存储正在初始化的Bean。正在初始化的集合里为空,返回false

 

 

  1.  isSingletonCurrentlyInCreation(beanName)返回false。
  2. getSingleton(beanName);没有获取到已经初始化的bean,返回null。

  1.  没有获得单例bean,走else方法
  2. else代码块中,上面一堆判断不重要,直接看下面。markBeanAsCreated方法标记这个bean,准备好创建了。

 

 

 

alreadyCreated用户存放准备好初始化的Bean.

 

 

 

 回到原来的方法,又是略过一段代码,判断userService是不是单例bean,肯定是,走这个方法。

 

 

  1.  是单例bean,走这个分支。
  2. 又是一个getSingleton方法,注意:这个是方法是两个参数,一个是beanName,一个是ObjectFactory<?>对象工厂,如下图:

 

 

  1.  首先看一下注释:返回给定名字的单例对象,如果没有注册过,那么就创建并注册。注册是什么??留一个疑问。
  2. ObjectFactory<?>是什么?它就是一个简单工厂,可以返回对象实例,怎么用,下面说。

 

 

  1. this.singletonObjects,又是它:缓存单例对象的集合。上面获取一遍,没有,这次还是没有。
  2. 在创建单例bean之前要做些事情:检查这个bean是否可以被创建,逻辑如下:

 

 

  1.  inCreationCheckExclusions:要排除的bean的集合。userService不是要排除的bean,这个判断是true。
  2. singletonsCurrentlyInCreation:正在创建的单例集合。把userService放在要被创建的集合,插入成功是true,前面还有一个‘!’,所以这个判断是false。不抛出异常。看到这里基本可以明白个大概了,循环依赖就是这里抛出的异常:二次检查userService时,userService在singletonsCurrentlyInCreation,说明userService正准备初始化,已经循环依赖了。可继续往下看:

 

 

 

 检查没问题,userService可以被创建,通过工厂获取对象。从ObjectFactory<?>这个对象工厂中获取bean:singletonFactory.getObject();

问题来了,这个工厂(singletonFactory)哪来的?怎么工作的?

 

 

 它是传进来的参数,怎么传进来的,再看看调用:

原来是createBean(beanName, mbd, args);返回的。那么就是说明createBean会返回一个工厂对象,这个工厂对象只生产userService这一个对象。

点进createBean方法,找到doCreateBean方法

 

 

  1.  在这个类里。
  2. 看注释,实际创建Bean的方法。跟踪调试看一下:

 

 

  1.  先从缓存中去掉,
  2. 再创建一个新的,点进去

 

 

 将BeanDefinition解析成Class,忽略上面这个图停留的地方,继续向下:

 

 

 判断是构造器注入的,点进去:

 

 

 这里有两个方法,走第二个,构造器解析:

 

 

  1.  在构造器解析类中
  2. 解析userService中有一个构造器
  3. 构造器参数类型是RoleService,继续向下走:

 

 

解析构造器参数,点进去:

 

 

 解析构造器参数的值,即参数名称:

 

 

 解析出来是roleService。容器会先将依赖的bean初始化好。然后关联起来。

 

 

 从这里开始,又是一顿分析roleSerice,过程和userService一样。分析到的结果是:roleSerice依赖userService。又去获取userService:

 

 

 这个胡汉三又回来了!

 

然后又是getSingleton(),往下看:

 

 

 

 现在准备初始化的bean集合有两个了,而且就有userService,下面看容器时怎么报错的:

又是往下走:到了这里

 

 

 又检查userService时候可以初始化:

 

 

 准备初始化的集合里面有userService,报错了!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

加载全部内容

相关教程
猜你喜欢
用户评论