@Async注解引发的报错探究二
回顾
我们现在正在探究循环依赖中加了@Async
注解产生的错误。
报的错误是:
Unsatisfied dependency expressed through field 'taskService';
nested exception is org.springframework.beans.factory.
BeanCurrentlyInCreationException:
Error creating bean with name 'taskServiceImpl':
Bean with name 'taskServiceImpl' has been injected into other
beans [robotServiceImpl] 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.
从上篇文章我们知道@EnableAsync
最终导入了一个bpp(AsyncAnnotationBeanPostProcessor
)。
我们还是简单看一下他的初始化吧:
因为他是一个BeanFactoryAware
,所以在走他的生命周期的时候,走到invokeAwareMethods
(bean实例化后需要初始化,这是初始化的第一步)的时候,就会接收到BeanFactory
。
这个不重要,重要的是他new了一个AsyncAnnotationAdvisor
:
/**
* Advisor that activates asynchronous method execution through the {@link Async}
* annotation. This annotation can be used at the method and type level in
* implementation classes as well as in service interfaces.
*
* <p>This advisor detects the EJB 3.1 {@code javax.ejb.Asynchronous}
* annotation as well, treating it exactly like Spring's own {@code Async}.
* Furthermore, a custom async annotation type may get specified through the
* {@link #setAsyncAnnotationType "asyncAnnotationType"} property.
*/
从注释可以看出就是这个东西来解析@Async
注解的。
同时, 他又是一个PointcutAdvisor
,也就是一个基于切点的Advisor
,那就是要进入aop的节奏了。
然后发生问题的业务类是RobotServiceImpl
和TaskServiceImpl
,他们有循环依赖,在TaskServiceImpl
有一个@Async
标注的方法。
RobotServiveImpl与TaskServiceImpl的循环依赖
为了清楚地debug,我将两个业务类干掉了:
继续走。
首先我们要创建的是RobotServiveImpl
,就是那个没有@Aysnc
注解的类。
这里我们知道了getSingleton
这个方法返回的就是原始版本的bean。
另外,在实例化之前,spring要做一个事情:
他把当前正在创建的bean的名字robotServiveImpl
放到一个正在创建的bean这样一个集合中。
在实例化后,因为robotServiveImpl
正在创建并且框架支持循环依赖,所以他要提前暴露。
他问一下:单例池里面有没有这个bean,没有的话,往两个集合中添加,从一个集合中移除,至于这些集合是什么东西,稍微记一下就行了。
现在要为robotServiveImpl
属性赋值了。
因为robotServiceImpl
中的taskService
是通过@Autowire
注入进来的,所以我们只需关注处理这个注解的bpp:AutowiredAnnotationBeanPostProcessor
。
这种bpp和在init方法执行前后作用的bpp不一样。他们是一种InstantiationAwareBeanPostProcessor
,他作用在bean的实例化前后,在实例化后,可以判断是否进行属性赋值(代码再往上走一点):
如果不需要属性赋值,那就直接return。
我们再回到AutowiredAnnotationBeanPostProcessor
的postProcessProperties
(为属性赋值)这里。
一路跟下去。
返回的matchingBeans
的key是taskServiceImpl
,value是一个Class
对象。
如果候选者是一个Class
对象(显然我们是),那就实例化:
这就又要走一遍bean的生命周期,去创建taskServiceImpl
了。
实例化之后要有属性注入,属性注入robotServiceImpl
的时候发现单例池中没有,然后又要去创建robotServiceImpl
。
那么现在,我们又走到了创建robotServiceImpl
这里。此时的目的是为了taskServiceImpl
的属性注入。
创建robotServiceImpl
的时候发现他没在单例池,但是在正在创建的集合中。
此时就能够从singletonFactories
取出来了(我们最早创建robotServiceImpl
有put
进去过)。
那么taskServiceImpl
中的robotServiceImpl
的属性注入就完成了(现在是在走taskServiceImpl
的生命周期)。
接下来要走taskServiceImpl
的初始化了。