spring 使用@Async注解实现异步执行
文本我们介绍spring中使用@Async注解实现异步执行功能。通过@Async注解的bean方法将在独立的线程中执行,即执行者无需等待调用方法完成。
Spring框架中的事件机制也支持异步处理。
启用异步支持
我们使用javaConfig方式配置启用异步支持,通过在配置类上增加注解@EnableAsync:
@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }
示例中注解可以满足需求,同时还有几个参数:
annotation – 缺省情况 @EnableAsync扫描Spring中@Async 注解和EJB 3.1 javax.ejb.Asynchronous注解; 该参数可以用于检查其他情况,如用户自定义注解。
mode – 指定使用通知类型 – JDK proxy-based 或 AspectJ weaving
proxyTargetClass – 指定使用的代理类型 – CGLIB 或 JDK; 该属性仅当 mode 被设置为AdviceMode.PROXY时有效。
order – 设置AsyncAnnotationBeanPostProcessor顺序; 缺省为最后一个,以便顾及所有已存在的代理。
异步处理也可以通过xml方式配置,使用task命名空间:
<task:executor id="myexecutor" pool-size="5" />
<task:annotation-driven executor="myexecutor"/>
@Async
首先我们需要了解其规则——@Async有两个限制:
- 必须仅应用在public方法上
- 自执行——从相同类中调用异步方法不起作用。
原因很简单——public方法能够被代理,自执行不工作是因为它绕过代理并直接调用底层方法。
无返回值方法
下面简单配置是针对无返回值方法实现异步调用:
@Async
public void asyncMethodWithVoidReturnType() {
System.out.println("Execute method asynchronously. "
+ Thread.currentThread().getName());
}
带返回值方法
@Async也可以应用在带返回值方法——通过Future包装返回值类型:
@Async
public Future<String> asyncMethodWithReturnType() {
System.out.println("Execute method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
return new AsyncResult<String>("hello world !!!!");
} catch (InterruptedException e) {
//
}
return null;
}
spring 也提供了实现Future接口的AsyncResult类,用于跟踪异步方法执行结果。下面示例是执行上面方法并返回Future类型的异步执行结果。
public void testAsyncAnnotationForMethodsWithReturnType()
throws InterruptedException, ExecutionException {
System.out.println("Invoking an asynchronous method. "
+ Thread.currentThread().getName());
Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();
while (true) {
if (future.isDone()) {
System.out.println("Result from asynchronous process - " + future.get());
break;
}
System.out.println("Continue doing something else. ");
Thread.sleep(1000);
}
}
Executor
Spring缺省使用SimpleAsyncTaskExecutor 实际以异步方式运行注解方法。缺省配置可以在两个级别上重新配置——应用级或每个方法级。
覆盖方法级Executor
相应Executor需要在配置类中声明:
@Configuration
@EnableAsync
public class SpringAsyncConfig {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
然后在@Async注解中指定执行器名称:
@Async("threadPoolTaskExecutor")
public void asyncMethodWithConfiguredExecutor() {
System.out.println("Execute method with configured executor - "
+ Thread.currentThread().getName());
}
覆盖应用级Executor
配置类应该实现AsyncConfigurer 接口,并实现getAsyncExecutor() 方法,方法中返回整个应用使用的执行器,即所有@Async注解的方法缺省使用该执行器异步执行方法:
@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return new SimpleAsyncTaskExecutor();
}
}
异常处理
当方法返回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);
}
}
}
在前节中,我们看到实现AsyncConfigurer 接口的配置类,下面增加异常部分配置。需要覆盖getAsyncUncaughtExceptionHandler() 方法,并返回我们自定义的异步异常处理器:
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
总结
本文我们讨论了spring中异步执行代码。首先了解基本配置和注解方法异步执行,也涉及高级配置——配置不同级别的执行器和异常处理策略。
本文参考链接:https://blog.csdn.net/neweastsun/article/details/80919415