现象及相关引用博客
https://segmentfault.com/a/1190000021217176
问题
Spring其实是可以帮助解决循环依赖的,但是在循环依赖的两个bean上有一个加入了@Async注解之后,在启动的时候就报错不能进行循环依赖。
1 | @Component |
对应的错误:1
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Bean with name 'a' has been injected into other beans [b] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
注意这里@Transaction虽然也是使用的代理,但是循环引用如果是@Transaction注解 是不影响启动的 可以在最早初始化类实例的时候就能拿到代理对象, 而async是在postProcessor后置处理器当中处理的,所以在循环引用时会放入原始对象而不是代理对象 在之后的check时会报错。这里要做下区分。
问题分析及解决方案
报错所在方法:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
1 | protected Object doCreateBean( ... ){ |
debug看到的对象注入:
可以看到@Async注解标注的Bean的创建代理的时机是在检查bean中引用的之后的。看@EnableAsync注解会通过AsyncConfigurationSelector注入AsyncAnnotationBeanPostProcessor这个后置处理器,在其实现了postProcessAfterInitalization方法,创建代理即在此中。
这里的根本原理是只要能被切面AsyncAnnotationAdvisor切入的Bean都会在后置处理器中生成一个代理对象(如果已经是代理对象,那么加入该切面即可),赋值为上边doCreateBean中的exposedObject作为返回值加入到spring容器中。
1 | // 关键是这里。当Bean初始化完成后这里会执行,这里会决策看看要不要对此Bean创建代理对象再返回~~~ |