Spring @Async注解

1.@Async注解使用条件

@Async源码
  • @Async注解一般用在类的方法上,如果用在类上,那么这个类所有的方法都是异步执行的;
  • 所使用的@Async注解方法的类对象应该是Spring容器管理的bean对象;
  • 调用异步方法类上需要配置上注解@EnableAsync

2.实现原理

为了更基础的分析异步调用背后的实现原理,这里选择使用xml配置文件的方式。使用xml配置文件方式时,一般会配置如下元素:

<task:annotation-driven executor="myExecutor" exception-handler="exceptionHandler"/>
<task:executor id="myExecutor" pool-size="5"/>
<bean id="exceptionHandler" class="com.abc.MyAsynExceptionHandler"/>

2.1 task标签

一般对于这种标签的解析都会有相应的NamespaceHandler,根据Spring命名的套路查找TaskNamespaceHandler类,具体代码如下:

TaskNamespaceHandler

(1)executor元素对应的ExecutorBeanDefinitionParser

ExecutorBeanDefinitionParser

该类从parse方法追踪具体的实现逻辑,这个类主要是根据executor元素中的配置,例如pool-size创建一个TaskExecutorFactoryBean对象,而在TaskExecutorFactoryBean中间接使用ThreadPoolExecutor创建了一个线程池,这个线程池会在annotation-driven元素解析类中用到

在TaskExecutorFactoryBean中可以看出:

TaskExecutorFactoryBean

(2)annotation-driven元素处理类AnnotationDrivenBeanDefinitionParser

AnnotationDrivenBeanDefinitionParser

默认情况下,如果没有配置mode属性,其值默认是proxy,使用代理模式,会创建一个AsyncAnnotationBeanPostProcessor,然后解析executor属性值和exception-handler属性值并将其设置到AsyncAnnotationBeanPostProcessor中。
该类实现了BeanFactoryAware接口,所以在其实例化时会执行setBeanFactory方法:

AsyncAnnotationBeanPostProcessor

创建AsyncAnnotationAdvisor对象,即给线程池创建了一个异步注解切面

AsyncAnnotationAdvisor

主要就是使用上面提到的executor元素解析得到的线程池和异常处理创建通知,使用@Async注解创建切入点
进入构建通知的方法中,buildAdvice(executor, exceptionHandler)

AsyncAnnotationAdvisor

AnnotationAsyncExecutionInterceptor间接实现了MethodInterceptor接口,而MethodInterceptor是AOP中切入点的处理器,处理器中最终被调用的是invoke方法,下面是invoke方法的源码:

AsyncExecutionInterceptor

doSubmit方法源码:

AsyncExecutionAspectSupport

AsyncAnnotationBeanPostProcessor类还间接实现了BeanPostProcessor接口,也就是说在bean初始化之前和之后会分别执行postProcessBeforeInitialization方法和postProcessAfterInitialization方法,而AsyncAnnotationBeanPostProcessor类的这两个方法是从AbstractAdvisingBeanPostProcessor类中继承来的,这里重点分析postProcessAfterInitialization方法,具体代码如下:

AbstractAdvisingBeanPostProcessor

创建代理可以使用Cglib或者jdk动态代理,这里选择JdkDynamicAopProxy深入分析,代理的创建这里就不深入分析了,这里重点关注一下调用代理时真正执行的invoke方法,方法体内容比较多,这里看一下如下重要代码:

JdkDynamicAopProxy

 

总结

Spring容器启动初始化bean时,判断类中是否使用了@Async注解,创建切入点和切入点处理器,根据切入点创建代理,在调用@Async注解标注的方法时,会调用代理,执行切入点处理器invoke方法,将方法的执行提交给线程池,实现异步执行。

所以,需要注意的一个错误用法是,如果A类的a方法(没有标注@Async)调用它自己的b方法(标注@Async)是不会异步执行的,因为从a方法进入调用的都是它本身,不会进入代理



作者:LZhan
链接:https://www.jianshu.com/p/69a7bbdaceeb
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章