spring - mvc - @Async
@Async
@EnableAsync
1.启用异步支持
@EnableAsync注释在我们的应用程序中启用异步处理。具有类似功能的 XML 等效项是使用executor属性的task:*命名空间。
让我们首先通过Java 配置启用异步处理。
我们将通过将@EnableAsync添加到配置类来完成此操作:
@Configuration @EnableAsync public class SpringAsyncConfig { ... }
启用注释就足够了。但也有一些简单的配置选项:
注解–默认情况下, @EnableAsync检测 Spring 的@Async注解和 EJB 3.1 javax.ejb.Asynchronous。我们也可以使用此选项来检测其他用户定义的注释类型。
mode 指示应使用的建议类型
proxyTargetClass指示应使用的代理类型仅当模式设置为AdviceMode.PROXY时,此属性才有效。
order设置应用AsyncAnnotationBeanPostProcessor的顺序默认情况下,它最后运行,以便它可以考虑所有现有代理。
我们还可以使用任务命名空间通过XML 配置启用异步处理:
<task:executor id="myexecutor" pool-size="5" /> <task:annotation-driven executor="myexecutor"/>
2.@Async注解
首先,让我们回顾一下规则。@Async有两个限制:
它必须仅应用于公共方法。
自调用(从同一个类中调用异步方法)将不起作用。
原因很简单:该方法需要公开 ,以便可以被代理。并且自调用不起作用,因为它绕过代理并直接调用底层方法。
这是配置具有 void 返回类型的方法以异步运行的简单方法:
@Async public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously. " + Thread.currentThread().getName()); }
我们还可以 通过将实际返回包装在 Future 中来将@Async应用于具有返回类型的方法:
@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); } }
3.执行器
默认情况下,Spring 使用SimpleAsyncTaskExecutor来实际异步运行这些方法。但我们可以在两个级别覆盖默认值:应用程序级别或单个方法级别。
4.在方法级别重写执行器
我们需要在配置类中声明所需的执行器:
@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()); }
5.在应用程序级别覆盖执行器
配置类应实现AsyncConfigurer接口。因此,它必须实现getAsyncExecutor()方法。在这里,我们将返回整个应用程序的执行器。现在,这成为运行用@Async注释的方法的默认执行器:
@Configuration @EnableAsync public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); threadPoolTaskExecutor.initialize(); return threadPoolTaskExecutor; } }
6.异常处理
当方法返回类型是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(); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理