一恬涧、AsyncConfigurerSupport 簡介
spring 中開啟異步只要在配置類加上
@EnableAsync 同時在service方法中加上@Async即可,注意service中的方法想要異步調(diào)用必須是通過注入調(diào)用(spring 代理)徽级。
@Service
public class ServiceA{
public void testA(){
testB();
}
@Async
public void testB(){
}
}
上述方法在調(diào)用testA時是同步調(diào)用气破,而非異步調(diào)用敛助,方法內(nèi)部的直接調(diào)用是沒有經(jīng)過spring 代理的搞监。
二冬筒、自定義異步調(diào)用的線程池和異常處理
AsyncConfigurerSupport 只定義了兩個方法分別用于自定義異步線程池疗涉、異步產(chǎn)生的異常捕獲坠七,通過實現(xiàn)此類即可實現(xiàn)自定義的異步線程池并淋。
demo如下:
新建子類 AsyncConfigHandler
@Configuration
@EnableAsync
public class AsyncConfigHandler extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(10);
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
@Bean // /actuator/shutdown
@Override
public Executor getAsyncExecutor2() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(new SomeTaskDecorator());
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(100);
executor.setAllowCoreThreadTimeOut(false);
executor.setKeepAliveSeconds(0);
executor.setThreadNamePrefix("DefaultAsync-");
executor.setWaitForTasksToCompleteOnShutdown(true); // ? ????? ??
executor.initialize();
return executor;
}
static class SomeTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
return () -> {
try {
log.info("Some Task Decorator Start");
runnable.run();
} finally {
log.info("Some Task Decorator End");
}
};
}
}
}
class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
System.out.println("class#method: " + method.getDeclaringClass().getName() + "#" + method.getName());
System.out.println("type : " + ex.getClass().getName());
System.out.println("exception : " + ex.getMessage());
}
}
編寫支持異步調(diào)用注解@Async的 DemoService
@Service
public class DemoService {
@Async
public void testAsync() throws InterruptedException {
System.out.println("這里是異步方法");
TimeUnit.SECONDS.sleep(10);
int i = 1 / 0;
}
}
編寫測試 controller
@RestController
@RequestMapping(value = "time")
public class DemoController {
@Autowired
private DemoService demoService;
@RequestMapping(value = "getTimeAndAsync")
public String getTimeAndAsync() throws InterruptedException {
demoService.testAsync();
return "異步加載=》" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
}
}
新建spring boot應用的步驟省略
訪問 http://localhost:8080/time/getTimeAndAsync
瀏覽器會立即輸出
異步加載=》2021-02-20 15:56:16
等待十秒鐘后會捕獲異常
class#method: com.example.bootdemo.service.DemoService#testAsync
type : java.lang.ArithmeticException
exception : / by zero
同步調(diào)用中可以采用 @RestControllerAdvice 和 @ExceptionHandler 注解捕獲全局的異常然后進行處理混稽,如果是異步調(diào)用則需要實現(xiàn) AsyncUncaughtExceptionHandler 進行單獨的額外處理召夹。