您好,登錄后才能下訂單哦!
這篇文章主要講解了“SpringBoot怎么優雅地實現異步調用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“SpringBoot怎么優雅地實現異步調用”吧!
同步編程:在同步編程中,任務一次執行一個,只有當一個任務完成時,下一個任務才會被解除阻塞。
異步編程:在異步編程中,可以同時執行多個任務。您可以在上一個任務完成之前轉到另一個任務。
在Spring Boot
中,我們可以使用@Async
注解來實現異步行為。
1.定義一個異步服務接口AsyncService.java
public interface AsyncService { void asyncMethod() throws InterruptedException; Future<String> futureMethod() throws InterruptedException; }
2.實現定義的接口AsyncServiceImpl.java
@Service @Slf4j public class AsyncServiceImpl implements AsyncService { @Async @Override public void asyncMethod() throws InterruptedException { Thread.sleep(3000); log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName()); } @Async @Override public Future<String> futureMethod() throws InterruptedException { Thread.sleep(5000); log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName()); return new AsyncResult<>("task Done"); } }
AsyncServiceImpl
是一個 spring
管理的 bean
。
您的異步方法必須是公共的,而且是被@Async
注解修飾。
返回類型被限制為 void
或 Future
。
3.定義一個控制器AsyncController.java
@EnableAsync @RestController @Slf4j public class AsyncController { @Autowired AsyncService asyncService; @GetMapping("/async") public String asyncCallerMethod() throws InterruptedException { long start = System.currentTimeMillis(); log.info("call async method, thread name: [{}]", Thread.currentThread().getName()); asyncService.asyncMethod(); String response = "task completes in :" + (System.currentTimeMillis() - start) + "milliseconds"; return response; } @GetMapping("/asyncFuture") public String asyncFuture() throws InterruptedException, ExecutionException { long start = System.currentTimeMillis(); log.info("call async method, thread name: [{}]", Thread.currentThread().getName()); Future<String> future = asyncService.futureMethod(); // 阻塞獲取結果 String taskResult = future.get(); String response = taskResult + "task completes in :" + (System.currentTimeMillis() - start) + "milliseconds"; return response; } }
關鍵點,需要添加啟用異步的注解@EnableAsync
,當然這個注解加在其他地方也ok得。
當外部調用該接口時,asyncMethod()
將由默認任務執行程序創建的另一個線程執行,主線程不需要等待完成異步方法執行。
4.運行一下
現在我們運行一下看看,是不是異步返回的。
可以看到調用/async
接口,最終一步調用了方法。
調用/asyncFuture
,發現返回5秒多,難道不是異步的嗎?其實也是異步的,看日志可以看出來,只不過我們返回的是Future
,調用Futrue.get()
是阻塞的。
我們現在看看如果異常方法中報錯了會怎么樣?修改異步代碼如下所示,會拋運行時異常:
再次執行異步接口,如下所示,會使用默認的線程池和異常處理。
我們也可以自定義異步方法的處理異常和異步任務執行器,我們需要配置 AsyncUncaughtExceptionHandler
,如下代碼所示:
@Configuration public class AsynConfiguration extends AsyncConfigurerSupport { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3); executor.setMaxPoolSize(4); executor.setThreadNamePrefix("asyn-task-thread-"); executor.setWaitForTasksToCompleteOnShutdown(true); executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new AsyncUncaughtExceptionHandler() { @Override public void handleUncaughtException(Throwable ex, Method method, Object... params) { System.out.println("Exception: " + ex.getMessage()); System.out.println("Method Name: " + method.getName()); ex.printStackTrace(); } }; } }
再次運行,得到的結果如下:
必須通過使用 @EnableAsync
注解注解主應用程序類或任何直接或間接異步方法調用程序類來啟用異步支持。主要通過代理模式實現,默認模式是 Proxy
,另一種是 AspectJ
。代理模式只允許通過代理攔截調用。永遠不要從定義它的同一個類調用異步方法,它不會起作用。
當使用 @Async
對方法進行注解時,它會根據“proxyTargetClass
”屬性為該對象創建一個代理。當 spring
執行這個方法時,默認情況下它會搜索關聯的線程池定義。上下文中唯一的 spring
框架 TaskExecutor bean
或名為“taskExecutor
”的 Executor bean
。如果這兩者都不可解析,默認會使用spring框架SimpleAsyncTaskExecutor
來處理異步方法的執行。
感謝各位的閱讀,以上就是“SpringBoot怎么優雅地實現異步調用”的內容了,經過本文的學習后,相信大家對SpringBoot怎么優雅地實現異步調用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。