栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

@Async注解引发的报错之循环依赖

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

@Async注解引发的报错之循环依赖

@Async注解引发的报错探究二

回顾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的初始化了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/727437.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号