@EnableAsync
和 @Configuration
类一起使用,如下所示,为整个Spring应用程序上下文启用注释驱动的异步处理
@Configuration @EnableAsync public class AppConfig { } 复制代码
@Component public class EmailService { @Async //无返回类型 public void send(String from, String to, String subject, String text) { //do send } @Async //有返回类型 public Future<String> send(String from, String to, String subject, String text) { System.out.println("Execute method asynchronously - " + Thread.currentThread().getName()); try { Thread.sleep(5000); return new AsyncResult<String>("hello world !!!!"); } catch (InterruptedException e) { // } return null; } } 复制代码
当我们调用 send()
方法时,这个任务就会异步去执行,
@Async
不仅可以用在方法上,还可以用在Bean类上,如果在类所有方法都是异步的
默认情况下,Spring将搜索关联的线程池定义:上下文中的唯一 TaskExecutor bean
,或者另一个名为“taskExecutor”的 Executor bean
。如果两者都不可解析,则将使用 SimpleAsyncTaskExecutor
处理异步方法调用。此外,具有 void
返回类型的带注解的方法不能将任何异常发送回调用者。默认情况下,仅记录下此类未捕获的异常。
要自定义所有这些,需要实现 AsyncConfigurer
并提供:
Executor
: 通过 getAsyncExecutor()
方法实现 AsyncUncaughtExceptionHandler
: 通过 getAsyncUncaughtExceptionHandler()
来实现
注意: AsyncConfigurer
配置类在应用程序上下文引导程序的早期初始化。如果你对其他 bean
有任何依赖,请确保尽可能地声明它们为 Lazy
,以便让它们通过其他后处理器。
@Configuration @EnableAsync public class AppConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(7); executor.setMaxPoolSize(42); executor.setQueueCapacity(11); executor.setThreadNamePrefix("MyExecutor-"); executor.setWaitForTasksToCompleteOnShutdown(true);//默认是false,即shutdown时会立即停止并终止当前正在执行任务 executor.setRejectedExecutionHandler((r, executor1) -> { for(;;) { try { executor1.getQueue().put(r); } catch (InterruptedException e) { e.printStackTrace(); } return; } });//指定被拒绝任务的处理方法,经过测试当并发量超过队列长度时可以继续执行,否则会抛出 org.springframework.core.task.TaskRejectedException异常 executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new CustomAsyncExceptionHandler();//自定义未捕获异常处理,参考 4 异常处理 小节 } } 复制代码
以上为应用级别重写Executor,Spring还提供方法级别重写: 开启Async并自定义Executor:
@Configuration @EnableAsync public class SpringAsyncConfig { @Bean(name = "threadPoolTaskExecutor") public Executor threadPoolTaskExecutor() { return new ThreadPoolTaskExecutor(); } } 复制代码
使用自定义Executor
@Async("threadPoolTaskExecutor") public void asyncMethodWithConfiguredExecutor() { System.out.println("Execute method with configured executor - " + Thread.currentThread().getName()); } 复制代码
当方法返回类型是 Future
时,异常处理很容易 - Future.get()方法将抛出异常。
但是,如果返回类型为void,则异常不会传播到调用线程。因此,我们需要添加额外的配置来处理异常。
我们将通过实现 AsyncUncaughtExceptionHandler
接口来创建自定义异步异常处理程序。当存在任何未捕获的异步异常时,将调用 handleUncaughtException()
方法:
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); } } } 复制代码