Recently, I encountered a requirement, which is that when the server receives a request, it does not require the task execution to be completed before returning the result. It can immediately return the result and let the task execute asynchronously. The first thing to consider is to start a new thread to execute the task or submit the task to a thread pool for execution. Both methods are OK. But Spring is so powerful, there must be some simpler method. I just Googled it and it really has it. Just use the two annotations @EnableAsync and @Async to be OK.
Add @Async annotation to the method
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
Add @EnableAsync annotation to the startup class or configuration class
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); }} test
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"); }}=================
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=============
From the above results, asyncService.asyncMethod("Async") is indeed executed asynchronously, and it uses a new thread.
Specify the Executor
From the above execution log, you can guess that Spring uses SimpleAsyncTaskExecutor to execute tasks asynchronously by default. You can search for this class. @Async can also specify a custom Executor.
Add a custom Executor to the startup class
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(); }}Specify the 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() + "====================); }}In this way, use threadPoolTaskExecutor when executing tasks asynchronously
Set the default Executor
As mentioned above, if @Async does not specify an Executor, the SimpleAsyncTaskExecutor is used by default. In fact, the default Executor can be configured using the AsyncConfigurer interface.
@Configurationpublic class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } } Exception capture
Exceptions may occur in asynchronous execution methods. We can use try catch inside the task to handle exceptions. When the task throws an exception, Spring also provides a method to catch it.
Implement the AsyncUncaughtExceptionHandler interface
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); } } }Implement the AsyncConfigurer interface rewrite getAsyncUncaughtExceptionHandler method
@Configurationpublic class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new CustomAsyncExceptionHandler(); } }Rewrite the asyncMethod method to make it throw an exception
@Async @Override public void asyncMethod(String arg) { System.out.println("arg:" + arg); System.out.println("=====" + Thread.currentThread().getName() + "=================); throw new NullPointerException(); }Running results:
=================
arg:Async
=====threadPoolTaskExecutor-1============
Exception message - Async NullPointerException
Method name - asyncMethod
Parameter value - Async
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.