回顾RobotServiveImpl与TaskServiceImpl的循环依赖
回顾我们现在正在探究循环依赖中加了@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:
他是一个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的初始化了。



