@Async注解引发的报错之解决

solution

答案

上篇文章中,我们知道了TaskServiceImpl在注入RobotServiceImpl前后从raw version变成了代理。而且我们希望找到dependentBeanMap这个map维护的地方。

在这里插入图片描述
在属性注入的代码里,我们看到了dependentBeanMap维护的地方。那么我们想:能不能不进这个方法?

其实最终的解决方案很简单,就是在注入的TaskService上加@Lazy注解:

在这里插入图片描述
TaskService就是有@Aysnc方法的服务。

问题是:为什么?

原理

假设我们加上了@Lazy注解,再次debug。容器要注入TaskController,然后属性注入的时候发现要注入TaskService,然后去创建TaskService,创建好后又要属性注入,发现有RobotService,然后又去创建RobotService,创建好后又要属性注入,我们就从这里开始。

在这里插入图片描述
在这里我们会去检查RobotServiceImpl中的TaskService属性是不是有@Lazy标签。

在这里插入图片描述
如果有这个注解,他就走buildLazyResolutionProxy(descriptor, beanName)。那我们就会进到这个方法。

在这里插入图片描述

在这里插入图片描述
他在这里生成了一个TaskService的代理返回了出去。到时候真正去获取TaskSerivce的时候会回调getTarget方法。

在这里插入图片描述
因为result有值了,所以autowiredBeanNames就是空的。

在这里插入图片描述
因为autowiredBeanNames为空,所以dependentBeanMap也没有值,或者说,他没有以TaskServiceImpl为key的值。

在这里插入图片描述
那么在RobotServiceImpl中注入的TaskService就是一个临时的代理对象。

我们走完RobotServiceImpl的生命周期,然后走TaskServiceImpl的生命周期。

在这里插入图片描述
TaskServiceImpl因为AsyncAnnotationBeanPostProcessor被做了一层代理,但是由于hasDependentBean(beanName)false,所以报错就不会出现了。

我们让TaskServiceImpl的生命周期走完。

在这里插入图片描述
在这里插入图片描述
在最后将TaskServiceImpl放到IOC容器的时候,RobotServiceImpl持有的TaskService也不是最终容器中的TaskService


那么,什么时候RobotServiceImpl才去获取真正在容器中的TaskService呢?

我们在TaskController中再增加一个要用RobotService的接口:

@RestController
public class TaskController {

    @Autowired
    private TaskService taskService;

    @Autowired
    private RobotService robotService;

    @GetMapping("/taskTime")
    public Long taskTime(){
        long start = System.currentTimeMillis();
        taskService.getTaskExecutionTime();
        long end = System.currentTimeMillis();
        return end-start;
    }

    @GetMapping("/sendCmd")
    public String sendCmd(){
        robotService.sendCmd("aaa");
        return "ok";
    }
}

我们请求sendCmd

一放行就来到了getTarget方法。

在这里插入图片描述
这时候才去容器中拿真正的TaskService

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值