【轉載】Spring @Async 原始碼解讀。
正文
1.引子
開啟非同步任務使用方法:
1).方法上加@Async註解
2).啟動類或者配置類上@EnableAsync
2.原始碼解析
雖然spring5已經出來了,但是我們還是使用的spring4,本文就根據spring-context-4.3.14.RELEASE.jar來分析原始碼。
[email protected]
org.springframework.scheduling.annotation.Async 原始碼註釋翻譯:
1 /**
2 * Annotation that marks a method as a candidate for <i>asynchronous</i> execution.
3 * Can also be used at the type level, in which case all of the type's methods are
4 * considered as asynchronous.該註解可以標記一個非同步執行的方法,也可以用來標註類,表示類中的所有方法都是非同步執行的。
5 *
6 * <p>In terms of target method signatures, any parameter types are supported.
7 * However, the return type is constrained to either { @code void} or
8 * {@link java.util.concurrent.Future}. In the latter case, you may declare the
9 * more specific {@link org.springframework.util.concurrent.ListenableFuture} or
10 * {@link java.util.concurrent.CompletableFuture} types which allow for richer
11 * interaction with the asynchronous task and for immediate composition with
12 * further processing steps.入參隨意,但返回值只能是void或者Future.(ListenableFuture介面/CompletableFuture類)
13 *
14 * <p>A {@code Future} handle returned from the proxy will be an actual asynchronous
15 * {@code Future} that can be used to track the result of the asynchronous method
16 * execution. However, since the target method needs to implement the same signature,
17 * it will have to return a temporary {@code Future} handle that just passes a value
18 * through: e.g. Spring's {@link AsyncResult}, EJB 3.1's {@link javax.ejb.AsyncResult},
19 * or {@link java.util.concurrent.CompletableFuture#completedFuture(Object)}.
20 * Future是代理返回的切實的非同步返回,用以追蹤非同步方法的返回值。當然也可以使用AsyncResult類(實現ListenableFuture介面)(Spring或者EJB都有)或者CompletableFuture類
21 * @author Juergen Hoeller
22 * @author Chris Beams
23 * @since 3.0
24 * @see AnnotationAsyncExecutionInterceptor
25 * @see AsyncAnnotationAdvisor
26 */
27 @Target({ElementType.METHOD, ElementType.TYPE})
28 @Retention(RetentionPolicy.RUNTIME)
29 @Documented
30 public @interface Async {
31
32 /**
33 * A qualifier value for the specified asynchronous operation(s).
34 * <p>May be used to determine the target executor to be used when executing this
35 * method, matching the qualifier value (or the bean name) of a specific
36 * {@link java.util.concurrent.Executor Executor} or
37 * {@link org.springframework.core.task.TaskExecutor TaskExecutor}
38 * bean definition.用以限定執行方法的執行器名稱(自定義):Executor或者TaskExecutor
39 * <p>When specified on a class level {@code @Async} annotation, indicates that the
40 * given executor should be used for all methods within the class. Method level use
41 * of {@code Async#value} always overrides any value set at the class level.
42 * @since 3.1.2 加在類上表示整個類都使用,加在方法上會覆蓋類上的設定
43 */
44 String value() default "";
45
46 }
上圖原始碼註釋已經寫的很清晰了哈,主要注意3點:
1)返回值:不要返回值直接void;需要返回值用AsyncResult或者CompletableFuture
2)可自定義執行器並指定例如:@Async("otherExecutor")
3)@Async 必須不同類間呼叫: A類--》B類.C方法()(@Async註釋在B類/方法中),如果在同一個類中呼叫,會變同步執行,例如:A類.B()-->A類[email protected] C(),原因是:底層實現是代理對註解掃描實現的,B方法上沒有註解,沒有生成相應的代理類。(當然把@Async加到類上也能解決但所有方法都非同步了,一般不這麼用!)
2.2 @EnableAsync
老規矩咱們直接看類註釋:
1 //開啟spring非同步執行器,類似xml中的task標籤配置,需要聯合@Configuration註解一起使用 2 Enables Spring's asynchronous method execution capability, similar to functionality found in Spring's <task:*> XML namespace. 3 To be used together with @Configuration classes as follows, enabling annotation-driven async processing for an entire Spring application context: 4 @Configuration 5 @EnableAsync 6 public class AppConfig { 7 8 } 9 MyAsyncBean is a user-defined type with one or more methods annotated with either Spring's @Async annotation, the EJB 3.1 @javax.ejb.Asynchronous annotation, or any custom annotation specified via the annotation() attribute. The aspect is added transparently for any registered bean, for instance via this configuration: 10 @Configuration 11 public class AnotherAppConfig { 12 13 @Bean 14 public MyAsyncBean asyncBean() { 15 return new MyAsyncBean(); 16 } 17 } 18 19 //預設情況下spring會先搜尋TaskExecutor型別的bean或者名字為taskExecutor的Executor型別的bean,都不存在使用SimpleAsyncTaskExecutor執行器 20 By default, Spring will be searching for an associated thread pool definition: either a unique TaskExecutor bean in the context, or an Executor bean named "taskExecutor" otherwise. If neither of the two is resolvable, a SimpleAsyncTaskExecutor will be used to process async method invocations. Besides, annotated methods having a void return type cannot transmit any exception back to the caller. By default, such uncaught exceptions are only logged. 21 To customize all this, implement AsyncConfigurer and provide: 22 your own Executor through the getAsyncExecutor() method, and your own AsyncUncaughtExceptionHandler through the getAsyncUncaughtExceptionHandler() method.//可實現AsyncConfigurer介面複寫getAsyncExecutor獲取非同步執行器,getAsyncUncaughtExceptionHandler獲取非同步未捕獲異常處理器 23 @Configuration 24 @EnableAsync 25 public class AppConfig implements AsyncConfigurer { 26 27 @Override 28 public Executor getAsyncExecutor() { 29 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 30 executor.setCorePoolSize(7); 31 executor.setMaxPoolSize(42); 32 executor.setQueueCapacity(11); 33 executor.setThreadNamePrefix("MyExecutor-"); 34 executor.initialize(); 35 return executor; 36 } 37 38 @Override 39 public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { 40 return MyAsyncUncaughtExceptionHandler(); 41 } 42 }
1 If only one item needs to be customized, null can be returned to keep the default settings. Consider also extending from AsyncConfigurerSupport when possible. 2 Note: In the above example the ThreadPoolTaskExecutor is not a fully managed Spring bean. Add the @Bean annotation to the getAsyncExecutor() method if you want a fully managed bean. In such circumstances it is no longer necessary to manually call the executor.initialize() method as this will be invoked automatically when the bean is initialized. 3 For reference, the example above can be compared to the following Spring XML configuration: 4 <beans> 5 6 <task:annotation-driven executor="myExecutor" exception-handler="exceptionHandler"/> 7 8 <task:executor id="myExecutor" pool-size="7-42" queue-capacity="11"/> 9 10 <bean id="asyncBean" class="com.foo.MyAsyncBean"/> 11 12 <bean id="exceptionHandler" class="com.foo.MyAsyncUncaughtExceptionHandler"/> 13 14 </beans> 15 //註解類和xml基本一致,但是使用註解類還可以自定義執行緒名字首(上面的AppConfig-》getAsyncExecutor-》setThreadNamePrefix) 16 The above XML-based and JavaConfig-based examples are equivalent except for the setting of the thread name prefix of the Executor; this is because the <task:executor> element does not expose such an attribute. This demonstrates how the JavaConfig-based approach allows for maximum configurability through direct access to actual componentry. 17 The mode() attribute controls how advice is applied: If the mode is AdviceMode.PROXY (the default), then the other attributes control the behavior of the proxying. Please note that proxy mode allows for interception of calls through the proxy only; local calls within the same class cannot get intercepted that way.//這裡就說明了@Async必須在不同方法中呼叫,即第一部分注意的第三點。 18 Note that if the mode() is set to AdviceMode.ASPECTJ, then the value of the proxyTargetClass() attribute will be ignored. Note also that in this case the spring-aspects module JAR must be present on the classpath, with compile-time weaving or load-time weaving applying the aspect to the affected classes. There is no proxy involved in such a scenario; local calls will be intercepted as well.//當然也可以用Aspect模式織入(需要引入spring-aspects模組需要的jar)
下面是原始碼:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface ç {
/**該屬性用來支援使用者自定義非同步註解,預設掃描spring的@Async和EJB3.1的@code @javax.ejb.Asynchronous
* Indicate the 'async' annotation type to be detected at either class
* or method level.
* <p>By default, both Spring's @{@link Async} annotation and the EJB 3.1
* {@code @javax.ejb.Asynchronous} annotation will be detected.
* <p>This attribute exists so that developers can provide their own
* custom annotation type to indicate that a method (or all methods of
* a given class) should be invoked asynchronously.
*/
Class<? extends Annotation> annotation() default Annotation.class;
/**標明是否需要建立CGLIB子類代理,AdviceMode=PROXY時才適用。注意設定為true時,其它spring管理的bean也會升級到CGLIB子類代理
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies.
* <p><strong>Applicable only if the {@link #mode} is set to {@link AdviceMode#PROXY}</strong>.
* <p>The default is {@code false}.
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with {@code @Async}.
* For example, other beans marked with Spring's {@code @Transactional} annotation
* will be upgraded to subclass proxying at the same time. This approach has no
* negative impact in practice unless one is explicitly expecting one type of proxy
* vs. another — for example, in tests.
*/
boolean proxyTargetClass() default false;
/**標明非同步通知將會如何實現,預設PROXY,如需支援同一個類中非非同步方法呼叫另一個非同步方法,需要設定為ASPECTJ
* Indicate how async advice should be applied.
* <p><b>The default is {@link AdviceMode#PROXY}.</b>
* Please note that proxy mode allows for interception of calls through the proxy
* only. Local calls within the same class cannot get intercepted that way; an
* {@link Async} annotation on such a method within a local call will be ignored
* since Spring's interceptor does not even kick in for such a runtime scenario.
* For a more advanced mode of interception, consider switching this to
* {@link AdviceMode#ASPECTJ}.
*/
AdviceMode mode() default AdviceMode.PROXY;
/**標明非同步註解bean處理器應該遵循的執行順序,預設最低的優先順序(Integer.MAX_VALUE,值越小優先順序越高)
* Indicate the order in which the {@link AsyncAnnotationBeanPostProcessor}
* should be applied.
* <p>The default is {@link Ordered#LOWEST_PRECEDENCE} in order to run
* after all other post-processors, so that it can add an advisor to
* existing proxies rather than double-proxy.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
執行流程:
如上圖,核心註解就是@Import(AsyncConfigurationSelector.class),一看就是套路ImportSelector
介面的selectImports()方法,原始碼如下:
1 /**查詢器:基於@EanableAsync中定義的模式AdviceMode加在@Configuration標記的類上,確定抽象非同步配置類的實現類
2 * Selects which implementation of {@link AbstractAsyncConfiguration} should be used based
3 * on the value of {@link EnableAsync#mode} on the importing {@code @Configuration} class.
4 *
5 * @author Chris Beams
6 * @since 3.1
7 * @see EnableAsync
8 * @see ProxyAsyncConfiguration
9 */
10 public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
11
12 private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
13 "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
14
15 /**
16 * {@inheritDoc}
17 * @return {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration} for
18 * {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()}, respectively
19 */
20 @Override
21 public String[] selectImports(AdviceMode adviceMode) {
22 switch (adviceMode) {
23 case PROXY://如果配置的PROXY,使用ProxyAsyncConfiguration
24 return new String[] { ProxyAsyncConfiguration.class.getName() };
25 case ASPECTJ://如果配置的ASPECTJ,使用ProxyAsyncConfiguration
26 return new String[] { ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME };
27 default:
28 return null;
29 }
30 }
31
32 }
我們就選一個類ProxyAsyncConfiguration(JDK介面代理)看一下具體實現:
1 /** 2 * {@code @Configuration} class that registers the Spring infrastructure beans necessary 3 * to enable proxy-based asynchronous method execution. 4 * 5 * @author Chris Beams 6 * @author Stephane Nicoll 7 * @since 3.1 8 * @see EnableAsync 9 * @see AsyncConfigurationSelector 10 */ 11 @Configuration 12 @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 13 public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration { 14 15 @Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME) 16 @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 17 public AsyncAnnotationBeanPostProcessor asyncAdvisor() { 18 Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected"); 19 AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();//新建一個非同步註解bean後處理器 20 Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation"); 21 //如果@EnableAsync中使用者自定義了annotation屬性,即非同步註解型別,那麼設定
if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) { 22 bpp.setAsyncAnnotationType(customAsyncAnnotation); 23 } 24 if (this.executor != null) {//Executor:設定執行緒任務執行器 25 bpp.setExecutor(this.executor); 26 } 27 if (this.exceptionHandler != null) {//AsyncUncaughtExceptionHandler:設定異常處理器 28 bpp.setExceptionHandler(this.exceptionHandler); 29 } 30 bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));//設定是否升級到CGLIB子類代理,預設不開啟 31 bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));//設定執行優先順序,預設最後執行 32 return bpp; 33 } 34 35 }
如上圖,ProxyAsyncConfiguration就兩點:
1.就是繼承了AbstractAsyncConfiguration類
2.定義了一個bean:AsyncAnnotationBeanPostProcessor
2.AbstractAsyncConfiguration原始碼:
相關推薦
【轉載】Spring @Async 原始碼解讀。
正文 1.引子 開啟非同步任務使用方法: 1).方法上加@Async註解 2).啟動類或者配置類上@EnableAsync 2.原始碼解析 雖然spring5已經出來了,但是我們還是使用的spring4,本文就根據spring-context-4.3.14.RELEASE.jar來分析原
【Spring IOC】Spring:原始碼解讀Spring IOC原理
一、什麼是Ioc/DI? IoC 容器:最主要是完成了完成物件的建立和依賴的管理注入等等。 先從我們自己設計這樣一個視角來考慮: 所謂控制反轉,就是把原先我們程式碼裡面需要實現的物件建立、依賴的程式碼,反轉給容器來幫忙實現。那麼必然的我們需要建立一個容器
【轉載】Spring AOP詳解 、 JDK動態代理、CGLib動態代理
rto 工廠 第一個 lec 僅支持 sel clas sleep gpo 原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspect Oriented Programing的簡稱,面向切面
【1】pytorch torchvision原始碼解讀之Alexnet
最近開始學習一個新的深度學習框架PyTorch。 框架中有一個非常重要且好用的包:torchvision,顧名思義這個包主要是關於計算機視覺cv的。這個包主要由3個子包組成,分別是:torchvision.datasets、torchvision.models、torchvision.trans
【轉載】spring-boot 專案跳轉到JSP頁面
原路徑:https://blog.csdn.net/qq_36820717/article/details/80008225 1、新建spring-boot專案 目錄結構如下 2、新建TestController.java檔案,內容如下 package com.example.contr
【轉載】spring boot 連結 虛擬機器(Linux) redis
原文:https://www.imooc.com/article/43279?block_id=tuijian_wz 前提是你已經安裝redis且支援遠端連線,redis的安裝這裡不再贅述,有需要的可以參考我的另一篇文章:centos 7.3上安裝redis。這裡主要講講如何判斷及設定redis支援遠端連線
【轉載】Spring和Spring MVC包掃描
轉自:http://www.cnblogs.com/junzi2099/p/8042476.html 在Spring整體框架的核心概念中,容器是核心思想,就是用來管理Bean的整個生命週期的,而在一個專案中,容器不一定只有一個,Spring中可以包括多個容器,而且容器有上下層關係,目前最常見的一
【轉載】Spring MVC @Autowired註入問題
這就是我 參數 int .net rec except 方法註入 null https 背景在IDEA升級2017版後,發現以前使用的 @Autowired 出現了個警告 Field injection is not recommended。 @Autowired的不推薦用
【轉載】spring-session負載均衡原理分析
註明轉載:https://www.jianshu.com/p/beaf18704c3c 第一部分:我會用循序漸進的方式來展示原始碼,從大家最熟悉的地方入手,而不是直接從系統啟動來debug原始碼。直接debug原始碼看到後來大家都會一頭霧水。 本文先從request.getSession()開始
【轉】Spring AMQP 原始碼分析 05
### 準備 ## 目標 瞭解 Spring AMQP Message Listener 如何處理異常 ## 前置知識 《Spring AMQP 原始碼分析 04 - MessageListener》 ## 相關資源 原始碼版本:Spring AMQP
【轉】Spring AMQP 原始碼分析 04
### 準備 ## 目標 瞭解 Spring AMQP 如何實現非同步訊息投遞(推模式) ## 前置知識 《RabbitMQ入門_05_多執行緒消費同一佇列》 ## 相關資源 原始碼版本:Spring AMQP 1.7.3.RELEASE ## 測試
【轉】Spring AMQP 原始碼分析 03
### 準備 ## 目標 瞭解 Spring AMQP 訊息轉化實現 ## 相關資源 ## 測試程式碼 gordon.study.rabbitmq.springamqp.JsonMessage.java ### 分析 ## Mes
【4】pytorch torchvision原始碼解讀之ResNet
pytorch框架中有一個非常重要且好用的包:torchvision,顧名思義這個包主要是關於計算機視覺cv的。這個包主要由3個子包組成,分別是:torchvision.datasets、torchvision.models、torchvision.transforms。
【5】pytorch torchvision原始碼解讀之DenseNet
pytorch框架中有一個非常重要且好用的包:torchvision,顧名思義這個包主要是關於計算機視覺cv的。這個包主要由3個子包組成,分別是:torchvision.datasets、torchvision.models、torchvision.transforms。
【轉載】Spring AOP
6.3.7. 例子 讓我們來看看在 Section 6.2.7, “例子” 提過併發鎖失敗重試的例子,如果使用schema對這個例子進行重寫是什麼效果。 因為併發鎖的關係,有時候business services可能會失敗(例如,死鎖失敗)。 如果重新嘗試一下,很有可能就會
【轉載】hmac_sha1.c原始碼, C語言中的HMAC_SHA1加密方法
感謝原作者,連結如下:http://blog.csdn.net/yanzhibo/article/details/8469608 /****************************************************************/ /* 80
【Spring Cloud 原始碼解讀】之 【這也太神奇了,RestTemplate加上一個@LoadBalanced註解就能實現負載均衡!】
前提概要: 前天,有個前端大佬問了我兩個問題:為啥不引入Ribbon依賴就能使用Ribbon?為啥RestTemplate加上@LoadBalanced註解就能負載均衡了?我也表示很疑惑,而我自己其實也真的沒去了解過,所以趁著工作不太忙,趕緊去研究一波。 第一個問題比較簡單,一般都是其他依賴引入了Ribbon
【Spring Cloud 原始碼解讀】之 【如何配置好OpenFeign的各種超時時間!】
關於Feign的超時詳解: 在Spring Cloud微服務架構中,大部分公司都是利用Open Feign進行服務間的呼叫,而比較簡單的業務使用預設配置是不會有多大問題的,但是如果是業務比較複雜,服務要進行比較繁雜的業務計算,那後臺很有可能會出現Read Timeout這個異常。 1、關於hystrix的熔斷
【轉載】開發者眼中的Spring與Java EE
客戶端 實現 意義 代理 produces 有著 hiberna arm 激情 轉載自:http://www.infoq.com/cn/news/2015/07/spring-javaee 在Java社區中,Spring與Java EE之爭是個永恒的話題。在這場爭論中,
【轉載】以此獻給所有OIer,以及所有競賽生,以及所有為夢想而不顧一切的人。
哪裏 的人 失誤 all blog 物理 cnblogs 現狀 煙臺 我們都是行走在鏡面邊緣的人。 低下頭看到的,是半個迷茫的自己,和半個不見底的深淵。 ——以此獻給所有OIer,以及所有競賽生,以及所有為夢想而不顧一切的人。 (名詞簡介:OIer,以信息學系列競賽為目標的