Spring循环依赖
2022-10-04 21:22:51 6 举报
登录查看完整内容
yyy
作者其他创作
大纲/内容
getSingleton(beanName,allowEarlyReference)
for(BeanPostProcessor bp : getBeanPostProcessors()){}遍历集合,得到每一个bp
getParentBeanFactory()检查bd是不是存在父工厂
getBeanPostProcessors得到所有的后置处理器
singletonObject为空 && allowEarlyReference=true
创建A
Spring通过调用getBeanPostProcessors()获取所有的后置处理器【内置的(6个)+程序员提供的】
Return直接返回
从二级缓存中找
该后置处理器结束
beanClass != null&&hasInstantiationAwareBeanPostProcessors()
第五次、六次调用后置处理器的时机:在实例化后第五六次调用后置处理器的作用:进行属性填充,以及@Autowired以及@Value、@Resource的自动注入
createBeanInstance开始实例化
这个里面的逻辑包括了一个重要的步骤 我们在bean标签中的initMethod方法
this.earlySingletonObjects.put()将得到的这个对象放到二级缓存中去
第三次调用后置处理器的时机:在实例化后第三次调用后置处理器的作用:调用属性合并后置处理器,进行属性合并
instantiateUsingFactoryMethod
ALL
强调:allowCircularReferences属性Spring默认是true,而此时由于我们这个Bean还在创建,doCreateBean()这个方法还没有结束,因此还没执行到afterSingletonCreation()这个方法,所以这个集合 isSingletonCurrentlyInCreation还存在当前创建的这个Bean的BeanName
ctor.newInstance(args)调用构造方法通过反射进行实例化
populateBean进行属性填充
这个属性很关键,通常正常的bean创建或者属性之间进行循环依赖都不会给该属性赋值,只有在配置类中@Bean方法之间进行相互依赖时,这个属性才会被赋值。具体可参考@Configruation注解使用
需要A
抛异常
invokeInitMethods【初始化】
getMergedLocalBeanDefinition合并bd转换为RootBd类型
N
doCreateBean(BeanName)
没拿到
doCreateBean()
如果不是仅仅做类型检查,而是创建 Bean 对象,则需要调用 markBeanAsCreated(String beanName) 方法,进行标记
initializeBean初始化
Spring通过调用getBeanPostProcessors()获取所有的后置处理器【内置的(6个)+程序员提供的】内置的6个入一下: ①:ApplicationContextAwareProcessor ②:ConfigurationClassPostProcessor ③:PostProcessorRegistrationDelegate$BeanPostProcessor ④:CommonAnnotationBeanPostProcessor ⑤:AutowiredAnnotationBeanPostProcessor⑥:ApplicationListenerDetector
不等于null
applyBeanPostProcessorsBeforeInitialization【初始化前】
getSingleton(beanName)
(mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName))判断是否出现了循环依赖
A创建时
从earlySingletonObjects中拿【二级缓存】
singletonObject == null && allowEarlyReference
从singletonObjects()拿【一级缓存】
第一次调用Bean的后置处理器
需要B
比如beanNameAware、BeanClassLoaderAware、BeanFactoryAware
true
第三次【每次都做了重载】
mbd.isSingleton()验证bd是不是单例
拿到了
mbd.getFactoryMethodName()得到该bd工厂方法名字等不等于null
beanFactory.getBean(factoryBeanName)根据工厂Bean重新在执行一次生命周期,进行实例化
创建B
能找到
A原始对象
One
Spring中每个后置处理器都是一个扩展点
this.earlySingletonObjects.get(beanName)从二级缓存中找
Y
调用getSingleton(beanName,singletonFactory)
A/B对应的Bean对象都创建完成
90%的情况下,我们只会满足第一个条件,第一次来拿一定是拿不到的,因为此时;该Bean还没有被创建出来。也没有放到单例池中去,所以第一个条件一定成立。接着判断第二个条件,而第二个条件来判断当前这个Bean是不是在创建中。此时条件也不会满足。但是如果满足这个条件,就继续往下面执行,那么什么时候这个条件才会满足呢,这个时候就是我们的Bean之间出现了循环依赖。
mbd.isSingleton()检查bd的单例属性
applyBeanPostProcessorsAfterInitialization【初始化后】
第四次调用后置处理器的时机:在实例化后第四次调用后置处理器的作用:将Aop提前
null
instantiateBean实例化方法
isPrototypeCurrentlyInCreation(beanName)检查是不是原形在创建中
得到一个Lmbda表达式理解成一个对象
checkMergedBeanDefinition检查当前创建的bd是不是抽象的
如果当前bean的创建过程中有依赖其它bean 那么要先创建被依赖的那个Bean。
singletonFactory.getObject()开始执行Lambda表达式
第七次、八次调用后置处理器的时机:在实属性填充后第七次八次调用后置处理器的作用:这个BeanPostProcessor接口 有很多的实现类 但是很多实现类 并没有在初始化前去做扩展 只有一个ApplicationContextAwareProcessor类做了扩展
this.singletonFactories.remove(beanName)把该对象从三级缓存中移除
ibp.postProcessMergedBeanDefinition调用后置处理器中postProcessMergedBeanDefinition方法
将B赋值给A对象
afterSingletonCreation(beanName)
执行InitializingBean.afterPropertiesSet()
addSingletonFactory【像三级缓存中添加一个Lambda表达式】
拿不到&&该Bean正在创建
整个循环依赖的最核心部分非常复杂细节单独介绍,里面完成了自动装配的原理。调用了@AutowiredAnnotationBeanPostProcessor或者@CommonAnnotationBeanPostProcessor
this.singletonsCurrentlyInDestruction检验这个单例bean在创建的时候会不会有工厂去销毁
applyBeanPostProcessorsBeforeInstantiation
仍然从单例池中获取【第一次仍然是空】
this.singletonFactories.get(beanName)从三级缓存中找
调用属性合并后置处理器,进行属性合并
A:A的原始对象
B创建完成
文本
CreateBean()
注意此时执行完Lambd得到的仍然是一个对象,还不是我们的bean
return 该对象
this.singletonObjects.get(beanName)从一级缓存中查
applyMergedBeanDefinitionPostProcessors
从三级缓存中找
此处传进去一个Lambda表达式作为参数,千万注意在此时这个Lambda表达式并没有得到执行,而是作为lamda表达式的函数体丢进去了,那么什么时候这个lambda表达式的函数体被执行呢?当我们去调用这个函数式接口中的getObject方法时,该函数体才会被执行。那么什么时候这个getObject方法会被执行呢,这个是不知道的。
等于null
earlySingletonObjects.get(beanName)从二级缓存中取
singletonObject == null && isSingletonCurrentlyInCreation(beanName)
invokeAwareMethods执行各种Aware
此时aservice仍然存在这个isSingletonCurrentlyInCreation的Set集合中
是不是出现循环依赖
获取不到
mbd.getDependsOn()检查bd的DependsOn属性
判断bp是不是postProcessBeforeInitialization类型
beforeSingletonCreation(beanName)
来推断构造方法的这个后置处理器是使用AutowiredAnnotationBeanPostProcessor注意:如果是使用默认构造方法进行实例化的话,也是推断不出来的。因为这个构造方法不能算是Spring推断出来的,所以也会返回null。
第二次调用后置处理器的时机:在实例化前第二次调用后置处理器的作用:推断构造方法比如Spring使用AutowiredAnnotationBeanPostProcessor完成构造方法推断。
hasInstantiationAwareBeanPostProcessors()
BeanUtils.instantiateClass(constructorToUse)通过BeanUtils这个工具类进行实例化
放到二级缓存从三级缓存中移除
typeCheckOnly检查是不是给该bean做类型校验
是
执行完这个lambda表达式后,根据创建出来的这个beanName作为key,从singletonsCurrentlyInCreation这个Set集合中将其移除
getSingleton(aservice)
Return object返回后置处理器得到的对象
这个lambda表达式执行就是执行addSingleton的方法体
addSingletonFactory放到三级缓存中去
生命周期结束
第一次
ibp.determineCandidateConstructors调用后置处理器中determineCandidateConstructors方法
ibp.postProcessProperties调用后置处理器中postProcessProperties方法
ibp.postProcessProperties调用后置处理器中postProcessBeforeInitialization方法
判断bp是不是InstantiationAwareBeanPostProcessor类型
既然getBean已经获取不到,那么讲道理应该根据这个beanName去开始完成创建了。但是Spring并没有这么做,Spring是怎么做的呢。Spring是在开始创建之前还做了一件别的事。去判断这个在创建的这个bean的名字在一个Set集合中存在不存在。这个set集合满足百分之90%的bean创建条件,除了循环依赖。所以在bean第一次创建的时候一定满足。除开这个条件之外,Spring还会把这个在创建的Bean添加到singletonsCurrentlyInCreation这个set集合中。
从一级缓存中找
执行Lambda表达式得到对象
Lambda表达式
没有出现循环依赖
populateBean属性填充
第二个bean第一次调用
singletonFactory.getObject()执行我们的Lamda表达式
第二次【该方法内部调用】
出现循环依赖
Spring中默认给allowEarlyReference设置为true
放入缓存
判断bp是不是MergedBeanDefinitionPostProcessor类型
判断bp是不是SmartInstantiationAwareBeanPostProcessor类型
0 条评论
回复 删除
下一页