首页 > 编程语言 > 详细

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

时间:2020-12-30 13:34:28      阅读:30      评论:0      收藏: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,报错了!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

原文:https://www.cnblogs.com/y13756204582/p/14210894.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!