组里有一个二方库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#doGetBeanDefaultSingletonBeanRegistry#getSingleton(String,true)singletonObjects这个缓存中没存,并且这个bean没有在创建中,所以不走这个分支 ❌
AbstractBeanFactory#markBeanAsCreated标记bean正在创建中DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>)AbstractAutowireCapableBeanFactory#createBean创建Bean实例AbstractAutowireCapableBeanFactory#resolveBeforeInstantiationbean实例化前操作,(可扩展,此时用户可以提前创建该对象,如果创建对象,则返回)❌AbstractAutoProxyCreator#postProcessBeforeInstantiation可以创建代理对象,但是用注解的时候没有创建代理对象
AbstractAutowireCapableBeanFactory#doCreateBean进入刚才函数式接口的表达式:真正创建beanAbstractAutowireCapableBeanFactory#createBeanInstance实例化bean,此时用BeanWrapper包裹beanDefaultSingletonBeanRegistry#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进入刚才函数式接口的表达式:真正创建beanAbstractAutowireCapableBeanFactory#createBeanInstance实例化bean,此时用BeanWrapper包裹beanDefaultSingletonBeanRegistry#addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)增加单例工厂,为aop(创建proxy)循环依赖做准备,三级缓存AbstractAutowireCapableBeanFactory#populateBean填充bean实例- 实例化Bean后置操作,如果显示实例化true,则直接返回 ❌
AutowiredAnnotationBeanPostProcessor#postProcessProperties@autowired注解通过该方法对属性进行注入- 获取到依赖的属性a(转3),拿到代理bean / 其他的存的是原始bean
AbstractAutowireCapableBeanFactory#initializeBean初始化bean,获得扩展的exposedObjectAbstractAutowireCapableBeanFactory#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这两个缓存中都没有,进入三级缓存:singletonFactoryAbstractAutowireCapableBeanFactory#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,完成循环依赖

