目的:源码调试构造器注入,看看是怎么报错的。
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. 判断是否需要实例化
- 循环遍历每个BeanDefinition,判读是不是 非抽象的&&单例的&&懒加载的 bean,不是跳过。
- 判断是不是工厂bean,是工厂bean,走处理工厂的方法。
- 不是工厂bean,是普通bean,初始化,继续向下
getSingleton(beanName);作用:从缓存中获取单例Bean。
singletonObjects用于缓存单例对象。从singletonObjects获取userService。由于是第一次获取,里面肯定没有。
调用isSingletonCurrentlyInCreation(beanName)方法,判断是不是在初始化中:
singletonsCurrentlyInCreation用于存储正在初始化的Bean。正在初始化的集合里为空,返回false
- isSingletonCurrentlyInCreation(beanName)返回false。
- getSingleton(beanName);没有获取到已经初始化的bean,返回null。
- 没有获得单例bean,走else方法
- else代码块中,上面一堆判断不重要,直接看下面。markBeanAsCreated方法标记这个bean,准备好创建了。
alreadyCreated用户存放准备好初始化的Bean.
回到原来的方法,又是略过一段代码,判断userService是不是单例bean,肯定是,走这个方法。
- 是单例bean,走这个分支。
- 又是一个getSingleton方法,注意:这个是方法是两个参数,一个是beanName,一个是ObjectFactory<?>对象工厂,如下图:
- 首先看一下注释:返回给定名字的单例对象,如果没有注册过,那么就创建并注册。注册是什么??留一个疑问。
- ObjectFactory<?>是什么?它就是一个简单工厂,可以返回对象实例,怎么用,下面说。
- this.singletonObjects,又是它:缓存单例对象的集合。上面获取一遍,没有,这次还是没有。
- 在创建单例bean之前要做些事情:检查这个bean是否可以被创建,逻辑如下:
- inCreationCheckExclusions:要排除的bean的集合。userService不是要排除的bean,这个判断是true。
- singletonsCurrentlyInCreation:正在创建的单例集合。把userService放在要被创建的集合,插入成功是true,前面还有一个'!',所以这个判断是false。不抛出异常。看到这里基本可以明白个大概了,循环依赖就是这里抛出的异常:二次检查userService时,userService在singletonsCurrentlyInCreation,说明userService正准备初始化,已经循环依赖了。可继续往下看:
检查没问题,userService可以被创建,通过工厂获取对象。从ObjectFactory<?>这个对象工厂中获取bean:singletonFactory.getObject();
问题来了,这个工厂(singletonFactory)哪来的?怎么工作的?
它是传进来的参数,怎么传进来的,再看看调用:
原来是createBean(beanName, mbd, args);返回的。那么就是说明createBean会返回一个工厂对象,这个工厂对象只生产userService这一个对象。
点进createBean方法,找到doCreateBean方法
- 在这个类里。
- 看注释,实际创建Bean的方法。跟踪调试看一下:
- 先从缓存中去掉,
- 再创建一个新的,点进去
将BeanDefinition解析成Class,忽略上面这个图停留的地方,继续向下:
判断是构造器注入的,点进去:
这里有两个方法,走第二个,构造器解析:
- 在构造器解析类中
- 解析userService中有一个构造器
- 构造器参数类型是RoleService,继续向下走:
解析构造器参数,点进去:
解析构造器参数的值,即参数名称:
解析出来是roleService。容器会先将依赖的bean初始化好。然后关联起来。
从这里开始,又是一顿分析roleSerice,过程和userService一样。分析到的结果是:roleSerice依赖userService。又去获取userService:
这个胡汉三又回来了!
然后又是getSingleton(),往下看:
现在准备初始化的bean集合有两个了,而且就有userService,下面看容器时怎么报错的:
又是往下走:到了这里
又检查userService时候可以初始化:
准备初始化的集合里面有userService,报错了!
原文转载:http://www.shaoqun.com/a/504467.html
yeepay:https://www.ikjzd.com/w/2574
feedback:https://www.ikjzd.com/w/159
目的:源码调试构造器注入,看看是怎么报错的。spring:5.2.3jdk:1.8一、准备 首先准备两个循环依赖的类:userService和roleServic<beanid="userService"class="com.chris.spring.service.UserServiceImpl"><constructor-argref
rfq:rfq
声网:声网
通知:Shopee多站点政策有更新调整啦!:通知:Shopee多站点政策有更新调整啦!
亚马逊ACoS:实现亚马逊广告和销售效率的关键是什么?:亚马逊ACoS:实现亚马逊广告和销售效率的关键是什么?
Joom运营小知识-准确申报产品重量:Joom运营小知识-准确申报产品重量
没有评论:
发表评论