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

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

环境: spring:5.2.3    jdk:1.8

(小弟第一次写,知道有待改进,路过的各位大哥,在评论里给点意见,我会逐步完善的,谢谢了~)

一、准备

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

<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时候。准确的说,是实例化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. org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons()

  • 获取BeanDefinition集合,可以看到userService和roleServic已经在容器中

  • 循环遍历每个BeanDefinition,判读是不是非抽象的&&单例的&&懒加载的 bean。
  • 如果是工厂bean,走处理工厂的方法;如果普通bean,调用getBean方法。

2. org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean()

  • 在doGetBean方法中,直接找到创建单例对象的这部分代码,如下图:

3. org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton()

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

  • this.singletonObjects,缓存已经实例化的单例对象的集合。userService还没有实例化。
  • 在创建单例bean之前要做些事情:检查这个bean是否可以被创建,调用beforeSingletonCreation(beanName)逻辑如下:

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

 

  •  通过上面的检查,userService可以被创建。调用singletonFactory.getObject();获取对象,即从ObjectFactory<?>这个对象工厂中获取userService。
  •  问题来了,这个工厂(singletonFactory)哪来的?怎么工作的?看函数声明:

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

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

4.org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()

  • 在createBean方法中,找到doCreateBean方法:

5.org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean()

  •  调用createBeanInstance(beanName, mbd, args)实例化bean

6.org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance()

  •  这里会判断是不是构造方法注入,点进去:

  •  这里有两个方法,创建一个构造方法解析器,然后解析构造方法

7.org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor()

  •  在这里解析到userService的构造方法中,有个参数是RoleService类型的,继续向下走:

  •  这里会解析构造方法的参数,点进去:

  •  解析构造方法参数的值,即参数名称。解析出来是roleService,解析过程如下:

  •  调用resolveReference(argName, ref)方法,获取roleService的实例,然后和userService关联起来。获取roleService代码如下:

  •  可以看到,容器调用getBean、doGetBean等方法,获取roleService。
  •  像userService一样,分析roleSerice的结果是:roleSerice依赖userService。容器又去获取userService,跳过roleService的过程,直接到达第二次获取userService:

  • 直接跳转到出现问题的地方,检查userService是否可以实例化:

  •  这时候发现,准备实例化的集合里面有userService,再次插入userService失败,说明发生了循环依赖,容器就报错了。

三、结论:

  singletonsCurrentlyInCreation的作用:记录准备好实例化的单例bean。如果里面出现了重复的bean,说明有循环依赖。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值