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

@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的节奏了。


然后发生问题的业务类是RobotServiceImplTaskServiceImpl,他们有循环依赖,在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。

我们再回到AutowiredAnnotationBeanPostProcessorpostProcessProperties(为属性赋值)这里。

在这里插入图片描述

一路跟下去。

在这里插入图片描述
返回的matchingBeans的key是taskServiceImpl,value是一个Class对象。

在这里插入图片描述
如果候选者是一个Class对象(显然我们是),那就实例化:

在这里插入图片描述
这就又要走一遍bean的生命周期,去创建taskServiceImpl了。

实例化之后要有属性注入,属性注入robotServiceImpl的时候发现单例池中没有,然后又要去创建robotServiceImpl

那么现在,我们又走到了创建robotServiceImpl这里。此时的目的是为了taskServiceImpl的属性注入。

在这里插入图片描述
创建robotServiceImpl的时候发现他没在单例池,但是在正在创建的集合中。

在这里插入图片描述
此时就能够从singletonFactories取出来了(我们最早创建robotServiceImplput进去过)。

在这里插入图片描述
在这里插入图片描述

那么taskServiceImpl中的robotServiceImpl的属性注入就完成了(现在是在走taskServiceImpl的生命周期)。

在这里插入图片描述
接下来要走taskServiceImpl的初始化了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值