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
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

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