组里有一个二方库TEST,通过实现BeanPostProcessor来对bean进行拦截,同时,在拦截的过程中对bean进行手动的aop代理,但是在开发环境中,当被代理的bean被循环依赖时,会初始化异常,特此debug一下
这篇文章会涉及到springbean的生命周期,aop,循环依赖
先导知识
- 一级缓存 - singletonObjects,初始化完成
- 二级缓存 - earlySingletonObjects,实例化完成(用于循环依赖)
- 三级缓存 - singletonFactory,其他实例化操作
Spring获得实例的三种bean:
- bean:原始bean
- exposedObject:扩展bean
- earlySingletonReference:从前两个缓存中拿到的bean(如果参数为true则有第三个缓存),提前暴露的循环依赖
假如说是类a被代理,同时a引用b,b也引用a,那么源码如下:
源码分析
首先获取实例a
- beanFactory.preInstantiateSingletons()->- AbstractBeanFactory#getBean->- AbstractBeanFactory#doGetBean- DefaultSingletonBeanRegistry#getSingleton(String,true)- singletonObjects这个缓存中没存,并且这个bean没有在创建中,所以不走这个分支 ❌
 
- AbstractBeanFactory#markBeanAsCreated标记bean正在创建中
- DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>)- AbstractAutowireCapableBeanFactory#createBean创建Bean实例- AbstractAutowireCapableBeanFactory#resolveBeforeInstantiationbean实例化前操作,(可扩展,此时用户可以提前创建该对象,如果创建对象,则返回)❌- AbstractAutoProxyCreator#postProcessBeforeInstantiation可以创建代理对象,但是用注解的时候没有创建代理对象
 
- AbstractAutowireCapableBeanFactory#doCreateBean进入刚才函数式接口的表达式:真正创建bean- AbstractAutowireCapableBeanFactory#createBeanInstance实例化bean,此时用BeanWrapper包裹bean
- DefaultSingletonBeanRegistry#addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)增加单例工厂,为aop(创建proxy)循环依赖做准备,三级缓存
- AbstractAutowireCapableBeanFactory#populateBean填充bean实例- 实例化Bean后置操作,如果显示实例化true,则直接返回 ❌
- AutowiredAnnotationBeanPostProcessor#postProcessProperties@autowired注解通过该方法对属性进行注入
- 获取到依赖的属性b(转2)
- AbstractAutowireCapableBeanFactory#initializeBean初始化bean,获得扩展的exposedObject,此时没有扩展- AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization初始化之前的扩展处理
- AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization初始化之后的扩展处理
- 没有扩展,所以bean==exposedObject / 对于TEST来说,此时exposedObject=proxy,且里面的参数没有被填充
 
- DefaultSingletonBeanRegistry#getSingleton(String,false)从一级缓存和二级缓存中获取对象赋值给- earlySingletonReference。此时第二个缓存中有该实例,且存的是proxy / 其他的存的是原始bean
- 因为bean==exposeObject,所以直接把proxy返回 / 对于TEST来说,此时bean!=exposedObject,同时系统检测该bean已经被其他bean利用,所以抛出异常
 
 
 
 
- 将该bean放入一级缓存,并将bean从二级缓存中删掉获取实例b 
 
- AbstractBeanFactory#getBean->- AbstractBeanFactory#doGetBean获取属性依赖- DefaultSingletonBeanRegistry#getSingleton(String,true)- singletonObjects这个缓存中没存,并且这个bean没有在创建中,所以不走这个分支 ❌
 
- AbstractBeanFactory#markBeanAsCreated标记bean正在创建中
- DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>)- AbstractAutowireCapableBeanFactory#createBean创建Bean实例- AbstractAutowireCapableBeanFactory#resolveBeforeInstantiationbean实例化前操作,(可扩展,此时用户可以提前创建该对象,如果创建对象,则返回)❌- AbstractAutoProxyCreator#postProcessBeforeInstantiation可以创建代理对象,但是用注解的时候没有创建代理对象
 
- AbstractAutowireCapableBeanFactory#doCreateBean进入刚才函数式接口的表达式:真正创建bean- AbstractAutowireCapableBeanFactory#createBeanInstance实例化bean,此时用BeanWrapper包裹bean
- DefaultSingletonBeanRegistry#addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)增加单例工厂,为aop(创建proxy)循环依赖做准备,三级缓存
- AbstractAutowireCapableBeanFactory#populateBean填充bean实例- 实例化Bean后置操作,如果显示实例化true,则直接返回 ❌
- AutowiredAnnotationBeanPostProcessor#postProcessProperties@autowired注解通过该方法对属性进行注入
- 获取到依赖的属性a(转3),拿到代理bean / 其他的存的是原始bean
- AbstractAutowireCapableBeanFactory#initializeBean初始化bean,获得扩展的exposedObject- AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization初始化之前的扩展处理
- AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization初始化之后的扩展处理
- 没有扩展,所以bean==exposeObject
 
- DefaultSingletonBeanRegistry#getSingleton(String,false)从一级缓存和二级缓存中获取对象。此时两个缓存均没有,且不允许进入第三个缓存,所以- earlySingletonReference为空
- 所以直接返回bean实例
 
 
 
 
- 将bean放入一级缓存获取实例a 
 
- AbstractBeanFactory#getBean->- AbstractBeanFactory#doGetBean获取属性依赖- DefaultSingletonBeanRegistry#getSingleton(String)- singletonObjects这个缓存中没存,但是bean已经在创建中了- DefaultSingletonBeanRegistry#getSingleton(String,true)- singletonObjects和- earlySingletonObjects这两个缓存中都没有,进入三级缓存:- singletonFactory
- AbstractAutowireCapableBeanFactory#getEarlyBeanReference这个就是三级缓存- AbstractAutoProxyCreator#wrapIfNecessary生成代理 / 其他的没有这一步
- 存入二级缓存(a, proxy)/ 其他的存的是原始bean
 
 
 
 
 
图片

问题原因
假如说是类a被代理,同时a引用b,b也引用a
对于正常的aop来说,会在b填充a的时候,a就已经是代理了
但是对于TEST的做法,它在b填充a的时候还是原来的bean,而在之后才代理,所以无法引用
解决方案
- 二方包:采用原生aop注解 
- 用户侧:循环依赖的非代理bean,增加@lazy注解,不在容器刷新时加载,而是在使用时加载 - 原因是增加lazy注解后,121233处不会经过,121235处 - earlySingletonReference为空,直接返回- exposedObject的代理类- 当循环依赖属性真正被引用的时候,它会去加载之前的代理bean,完成循环依赖 

