一、@Async注解簡介
Spring為任務排程與異步方法執行提供了注解支援。通過在方法上設定@Async注解,可使得方法被異步調用。也就是說調用者會在調用時立即傳回,而被調用方法的實際執行是交給Spring的TaskExecutor來完成。
二、配置與使用
我們可以使用springBoot預設的線程池,不過一般我們會自定義線程池(因為比較靈活)
@Configuration
@EnableAsync
public class TaskExecutorConfig {
/**
* 建立異步調用的線程池
* @return
*/
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(200);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("taskExecutor-");
// 用來設定線程池關閉的時候等待所有任務都完成再繼續銷毀其他的Bean,這樣這些異步任務的銷毀就會先于Redis線程池的銷毀
executor.setWaitForTasksToCompleteOnShutdown(true);
// 設定線程池中任務的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確定應用最後能夠被關閉,而不是阻塞住
executor.setAwaitTerminationSeconds(60);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
編寫異步方法
@Service
public class AsyncTaskService {
@Async("taskExecutor")
public void doTask(){
try {
Thread.sleep(5 * 1000);
System.out.println("睡眠完成");
} catch (Exception e){
System.out.println(e.getMessage());
}
}
}
進行測試
/**
* 修改使用者
*
* @return 結果
*/
@GetMapping("/task")
@ResponseBody
public Map<String, Object> task() {
System.out.println("---- 執行前 -------");
asyncTaskService.doTask();
System.out.println("---- 執行後 -------");
Map<String, Object> resultMap = new HashMap<>(16);
resultMap.put("code", 200);
resultMap.put("msg", "執行成功");
return resultMap;
}
通路 http://localhost:8765/task
異步調用成功
三、注意事項
如下方式會使@Async失效
- 異步方法使用static修飾
- 異步類沒有使用@Component注解(或其他注解)導緻spring無法掃描到異步類
- 異步方法不能與被調用的異步方法在同一個類中
- 類中需要使用@Autowired或@Resource等注解自動注入,不能自己手動new對象
- 如果使用SpringBoot架構必須在啟動類中增加@EnableAsync注解