1 Spring 版本
5.1.4.RELEASE
2 基本使用
2.1 开启对异步任务的支持
@EnableAsync
和@Configuration
类一起使用,如下所示,为整个Spring应用程序上下文启用注释驱动的异步处理
@Configuration
@EnableAsync
public class AppConfig {
}
复制代码
2.2 编写异步任务
@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类上,如果在类所有方法都是异步的
3 自定义Executor
默认情况下,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 异常处理 小节
}
}
复制代码
3.1 在方法级别自定义Executor
以上为应用级别重写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());
}
复制代码
4 异常处理
当方法返回类型是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);
}
}
}
复制代码
5 原理
概括来说,Spring使用的是AOP技术来实现的异步任务,详细原理之后再总结。