1 Spring 版本
5.1.4.RELEASE
2 基本使用
2.1 開啟對非同步任務的支援
@EnableAsync
和@Configuration
類一起使用,如下所示,為整個Spring應用程式上下文啟用註釋驅動的非同步處理
@Configuration
@EnableAsync
public class AppConfig {
}
複製程式碼
2.2 編寫非同步任務
@Component
public class EmailService {
@Async
//無返回型別
public void send(String from, String to, String subject, String text) {
//do send
}
@Async
//有返回型別
public Future<String> send(String from, String to, String subject, String text) {
System.out.println("Execute method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
return new AsyncResult<String>("hello world !!!!");
} catch (InterruptedException e) {
//
}
return null;
}
}
複製程式碼
當我們呼叫send()
方法時,這個任務就會非同步去執行,@Async
不僅可以用在方法上,還可以用在Bean類上,如果在類所有方法都是非同步的
3 自定義Executor
預設情況下,Spring將搜尋關聯的執行緒池定義:上下文中的唯一TaskExecutor bean
,或者另一個名為“taskExecutor”的Executor bean
。如果兩者都不可解析,則將使用SimpleAsyncTaskExecutor
處理非同步方法呼叫。此外,具有void
返回型別的帶註解的方法不能將任何異常傳送回撥用者。預設情況下,僅記錄下此類未捕獲的異常。
要自定義所有這些,需要實現AsyncConfigurer
並提供:
- 自定義
Executor
: 通過getAsyncExecutor()
方法實現 - 自定義
AsyncUncaughtExceptionHandler
: 通過getAsyncUncaughtExceptionHandler()
來實現
注意:AsyncConfigurer
配置類在應用程式上下文載入程式的早期初始化。如果你對其他bean
有任何依賴,請確保儘可能地宣告它們為Lazy
,以便讓它們通過其他後處理器。
@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.setWaitForTasksToCompleteOnShutdown(true);//預設是false,即shutdown時會立即停止並終止當前正在執行任務
executor.setRejectedExecutionHandler((r, executor1) -> {
for(;;) {
try {
executor1.getQueue().put(r);
} catch (InterruptedException e) {
e.printStackTrace();
}
return;
}
});//指定被拒絕任務的處理方法,經過測試當併發量超過佇列長度時可以繼續執行,否則會丟擲 org.springframework.core.task.TaskRejectedException異常
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();//自定義未捕獲異常處理,參考 4 異常處理 小節
}
}
複製程式碼
3.1 在方法級別自定義Executor
以上為應用級別重寫Executor,Spring還提供方法級別重寫: 開啟Async並自定義Executor:
@Configuration
@EnableAsync
public class SpringAsyncConfig {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
複製程式碼
使用自定義Executor
@Async("threadPoolTaskExecutor")
public void asyncMethodWithConfiguredExecutor() {
System.out.println("Execute method with configured executor - "
+ Thread.currentThread().getName());
}
複製程式碼
4 異常處理
當方法返回型別是Future
時,異常處理很容易 - Future.get()方法將丟擲異常。
但是,如果返回型別為void,則異常不會傳播到呼叫執行緒。因此,我們需要新增額外的配置來處理異常。
我們將通過實現AsyncUncaughtExceptionHandler
介面來建立自定義非同步異常處理程式。當存在任何未捕獲的非同步異常時,將呼叫handleUncaughtException()
方法:
public class CustomAsyncExceptionHandler
implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(
Throwable throwable, Method method, Object... obj) {
System.out.println("Exception message - " + throwable.getMessage());
System.out.println("Method name - " + method.getName());
for (Object param : obj) {
System.out.println("Parameter value - " + param);
}
}
}
複製程式碼
5 原理
概括來說,Spring使用的是AOP技術來實現的非同步任務,詳細原理之後再總結。