最近遇到一個(gè)需求,就是當(dāng)服務(wù)器接到請求并不需要任務(wù)執(zhí)行完成才返回結(jié)果,可以立即返回結(jié)果,讓任務(wù)異步的去執(zhí)行。開始考慮是直接啟一個(gè)新的線程去執(zhí)行任務(wù)或者把任務(wù)提交到一個(gè)線程池去執(zhí)行,這兩種方法都是可以的。但是 Spring 這么強(qiáng)大,肯定有什么更簡單的方法,就 google 了一下,還真有呢。就是使用 @EnableAsync 和 @Async 這兩個(gè)注解就 ok 了。
給方法加上 @Async 注解
1
2
3
4
5
6
|
package me.deweixu.aysncdemo.service; public interface AsyncService { void asyncMethod(String arg); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package me.deweixu.aysncdemo.service.ipml; import me.deweixu.aysncdemo.service.AsyncService; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class AsyncServiceImpl implements AsyncService { @Async @Override public void asyncMethod(String arg) { System.out.println( "arg:" + arg); System.out.println( "=====" + Thread.currentThread().getName() + "=========" ); } } |
@EnableAsync
在啟動(dòng)類或者配置類加上 @EnableAsync 注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package me.deweixu.aysncdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; @EnableAsync @SpringBootApplication public class AysncDemoApplication { public static void main(String[] args) { SpringApplication.run(AysncDemoApplication. class , args); } } |
測試
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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 ) @SpringBootTest public 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] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
arg:Async
=====SimpleAsyncTaskExecutor-1=========
從上面的結(jié)果看 asyncService.asyncMethod("Async") 確實(shí)異步執(zhí)行了,它使用了一個(gè)新的線程。
指定 Executor
從上面執(zhí)行的日志可以猜測到 Spring 默認(rèn)使用 SimpleAsyncTaskExecutor 來異步執(zhí)行任務(wù)的,可以搜索到這個(gè)類。@Async 也可以指定自定義的 Executor。
在啟動(dòng)類中增加自定義的 Executor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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 @SpringBootApplication public class AysncDemoApplication { public static void main(String[] args) { SpringApplication.run(AysncDemoApplication. class , args); } @Bean (name = "threadPoolTaskExecutor" ) public Executor threadPoolTaskExecutor() { return new ThreadPoolTaskExecutor(); } } |
指定 Executor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package me.deweixu.aysncdemo.service.ipml; import me.deweixu.aysncdemo.service.AsyncService; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class AsyncServiceImpl implements AsyncService { @Async ( "threadPoolTaskExecutor" ) @Override public void asyncMethod(String arg) { System.out.println( "arg:" + arg); System.out.println( "=====" + Thread.currentThread().getName() + "=========" ); } } |
這樣在異步執(zhí)行任務(wù)的時(shí)候就使用 threadPoolTaskExecutor
設(shè)置默認(rèn)的 Executor
上面提到如果 @Async 不指定 Executor 就默認(rèn)使用 SimpleAsyncTaskExecutor,其實(shí)默認(rèn)的 Executor 是可以使用 AsyncConfigurer 接口來配置的
1
2
3
4
5
6
7
|
@Configuration public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } } |
異常捕獲
在異步執(zhí)行的方法中是可能出現(xiàn)異常的,我們可以在任務(wù)內(nèi)部使用 try catch 來處理異常,當(dāng)任務(wù)拋出異常時(shí),Spring 也提供了捕獲它的方法。
實(shí)現(xiàn) AsyncUncaughtExceptionHandler 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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); } } } |
實(shí)現(xiàn) AsyncConfigurer 接口重寫 getAsyncUncaughtExceptionHandler 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Configuration public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new CustomAsyncExceptionHandler(); } } |
改寫 asyncMethod 方法使它拋出異常
1
2
3
4
5
6
7
|
@Async @Override public void asyncMethod(String arg) { System.out.println( "arg:" + arg); System.out.println( "=====" + Thread.currentThread().getName() + "=========" ); throw new NullPointerException(); } |
運(yùn)行結(jié)果:
=====main=========
arg:Async
=====threadPoolTaskExecutor-1=========
Exception message - Async NullPointerException
Method name - asyncMethod
Parameter value - Async
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://segmentfault.com/a/1190000013974727