springboot @EnableAsync @Async源码笔记

本人博客原地址:springboot @EnableAsync @Async源码笔记
创作时间:2019.06.27 17:20:52

基于springboot2.1.4

首先上本次debug的代码

@SpringBootApplication
//@Import(HelloConfiguration.class)
/**
 * proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。
 * 如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用
 * (这时需要cglib库)。如果proxy-target-class属值被设置为false或者这个
 * 属性被省略,那么标准的JDK 基于接口的代理
 *
 */
@EnableAsync(proxyTargetClass=true)
public class AutotestApplication {

    @PostConstruct
    public void init(){
        System.out.println("AutotestApplication init...");
    }
    public static void main(String[] args) {
        SpringApplication.run(AutotestApplication.class, args);
    }
@Component
public class TestService implements IService{

    @Async
    public void doService(){
        System.out.println("test Service");
    }
}
@RestController
public class TestController {

    @Autowired
    TestService testService;

    @RequestMapping("/hello")
    public String sayHello(){
        testService.doService();
        return "hello";
    }
}
1、首先来看下@EnableAsync

有图可知,通过annotation可设置除@Async之外的注解,使其也被拦截成异步处理
关于org.springframework.scheduling.annotation.AsyncConfigurationSelector
在定义bean的阶段,有兴趣可参考这里的3.1.2 过程中,会处理到
org.springframework.context.annotation.AdviceModeImportSelector#selectImports(org.springframework.core.type.AnnotationMetadata)–>org.springframework.scheduling.annotation.AsyncConfigurationSelector#selectImports会根据mode的值选择不同的配置类本文主要讲红圈中的org.springframework.scheduling.annotation.ProxyAsyncConfigurationbeanPostProcessor添加时机,bean 的实例化过程
由于org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor已经实例化并添加到BeanFactory中,在getBean的时候都会执行到改processor的前置后置方法。
AsyncAnnotationBeanPostProcessor类的父类AbstractBeanFactoryAwareAdvisingPostProcessor中实现了BeanFactoryAware接口,在调用前后置方法前,会先执行该接口方法会先执行org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods,此处会执行到AsyncAnnotationBeanPostProcessor的setBeanFactory方法;
注意,此处的拦截器实现的是org.aopalliance.intercept.MethodInterceptor,不是CGLIB的后面容易混淆,先记住这里

2、现在来看看如果执行AsyncAnnotationBeanPostProcessor的前后置方法完成某个Bean的代理设置


如果需要处理的bean是个Advised的实现类,则将this.advisor添加到这个bean的advisor列表中,这个bean的所有advice(通常实现成org.aopalliance.intercept.MethodInterceptor的实现类)会以链式调用的方式执行拦截
org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)->org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy当optimize或者proxyTargetClass设置为true,或者没有实现任何接口,且targetclass不是接口或者proxy类,使用CGlib代理方式

调用其getProxy方法org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)此处通过Enhancer生成代理对象,enhancer/ProxyFactory的使用可以参考这里其中的getCallbacks方法中添加的callback有四五个,本文只关注最重要的一个org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor(这个interceptor实现的接口是org.springframework.cglib.proxy.MethodInterceptor跟上面的org.aopalliance.intercept.MethodInterceptor不是同一个,请注意区分)在执行Enhancer生成代理的对象的目标方法的时候,会被DynamicAdvisedInterceptor拦截,执行其intercept方法图中的targetSource.getTarget();就是获取目标代理对象具体看org.springframework.aop.TargetSource接口实现类对getTarget方法如何实现bean的获取

本次的advice只有一个,那就是之前设置在org.springframework.scheduling.annotation.AsyncAnnotationAdvisor中的org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor#AnnotationAsyncExecutionInterceptor(java.util.concurrent.Executor, org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler)进入其invoke方法org.springframework.aop.interceptor.AsyncExecutionInterceptor#invoke
接下来看看提交任务
因此,当@Async注解的方法返回值类型为CompletableFuture、ListenableFuture、Future时,才有返回值。
具体执行task如下:

		Callable<Object> task = () -> {
			try {
//  提交任务后执行此处的 invocation.proceed();继续执行调用链,不过本demo没有后续的advice,、
//   此时会进入org.springframework.aop.framework.ReflectiveMethodInvocation#proceed中调用目标方法的位置
				Object result = invocation.proceed();
				if (result instanceof Future) {
					return ((Future<?>) result).get();
				}
			}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值