最近遇到一個需求,就是當服務器接到請求並不需要任務執行完成才返回結果,可以立即返回結果,讓任務異步的去執行。開始考慮是直接啟一個新的線程去執行任務或者把任務提交到一個線程池去執行,這兩種方法都是可以的。但是Spring 這麼強大,肯定有什麼更簡單的方法,就google 了一下,還真有呢。就是使用@EnableAsync 和@Async 這兩個註解就ok 了。
給方法加上@Async 註解
package me.deweixu.aysncdemo.service;public interface AsyncService { void asyncMethod(String arg);} package me.deweixu.aysncdemo.service.ipml;import me.deweixu.aysncdemo.service.AsyncService;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;@Servicepublic class AsyncServiceImpl implements AsyncService { @Async @Override public void asyncMethod(String arg) { System.out.println("arg:" + arg); System.out.println("=====" + Thread.currentThread().getName() + "========="); }} @EnableAsync
在啟動類或者配置類加上@EnableAsync 註解
package me.deweixu.aysncdemo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableAsync;@EnableAsync@SpringBootApplicationpublic class AysncDemoApplication { public static void main(String[] args) { SpringApplication.run(AysncDemoApplication.class, args); }}測試
package me.deweixu.aysncdemo;import me.deweixu.aysncdemo.service.AsyncService;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)@SpringBootTestpublic class AysncDemoApplicationTests { @Autowired AsyncService asyncService; @Test public void testAsync() { System.out.println("=====" + Thread.currentThread().getName() + "========="); asyncService.asyncMethod("Async"); }}=====main=========
2018-03-25 21:30:31.391 INFO 28742 --- [ main] .saAnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
arg:Async
=====SimpleAsyncTaskExecutor-1=========
從上面的結果看asyncService.asyncMethod("Async") 確實異步執行了,它使用了一個新的線程。
指定Executor
從上面執行的日誌可以猜測到Spring 默認使用SimpleAsyncTaskExecutor 來異步執行任務的,可以搜索到這個類。 @Async 也可以指定自定義的Executor。
在啟動類中增加自定義的Executor
package me.deweixu.aysncdemo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;@EnableAsync@SpringBootApplicationpublic class AysncDemoApplication { public static void main(String[] args) { SpringApplication.run(AysncDemoApplication.class, args); } @Bean(name = "threadPoolTaskExecutor") public Executor threadPoolTaskExecutor() { return new ThreadPoolTaskExecutor(); }}指定Executor
package me.deweixu.aysncdemo.service.ipml;import me.deweixu.aysncdemo.service.AsyncService;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;@Servicepublic class AsyncServiceImpl implements AsyncService { @Async("threadPoolTaskExecutor") @Override public void asyncMethod(String arg) { System.out.println("arg:" + arg); System.out.println("=====" + Thread.currentThread().getName() + "========="); }}這樣在異步執行任務的時候就使用threadPoolTaskExecutor
設置默認的Executor
上面提到如果@Async 不指定Executor 就默認使用SimpleAsyncTaskExecutor,其實默認的Executor 是可以使用AsyncConfigurer 接口來配置的
@Configurationpublic class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } }異常捕獲
在異步執行的方法中是可能出現異常的,我們可以在任務內部使用try catch 來處理異常,當任務拋出異常時,Spring 也提供了捕獲它的方法。
實現AsyncUncaughtExceptionHandler 接口
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); } } }實現AsyncConfigurer 接口重寫getAsyncUncaughtExceptionHandler 方法
@Configurationpublic class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new CustomAsyncExceptionHandler(); } }改寫asyncMethod 方法使它拋出異常
@Async @Override public void asyncMethod(String arg) { System.out.println("arg:" + arg); System.out.println("=====" + Thread.currentThread().getName() + "========="); throw new NullPointerException(); }運行結果:
=====main=========
arg:Async
=====threadPoolTaskExecutor-1=========
Exception message - Async NullPointerException
Method name - asyncMethod
Parameter value - Async
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。