原文地址:http://www.baeldung.com/spring-async

1. Overview

In this article, we’ll explore the asynchronous execution support in Spring – and the @Async annotation.

Simply put – annotating a method of a bean with @Async will make it execute in a separate thread i.e. the caller will not wait for the completion of the called method.

One interesting aspect in Spring is that the event support in the framework also has support for async processing if you want to go that route.

2. Enable Async Support

Let’s start by enabling asynchronous processing with Java configuration – by simply adding the @EnableAsync to a configuration class:

1
2
3
@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }

The enable annotation is enough, but as you’d expect, there are also a few simple options for configuration as well:

  • annotation – by default, @EnableAsync detects Spring’s @Async annotation and the EJB 3.1 javax.ejb.Asynchronous; this option can be used to detect other, user-defined annotation types as well
  • mode – indicates the type of advice that should be used – JDK proxy-based or AspectJ weaving
  • proxyTargetClass – indicates the type of proxy that should be used – CGLIB or JDK; this attribute has effect only if the mode is set to AdviceMode.PROXY
  • order – sets the order in which AsyncAnnotationBeanPostProcessor should be applied; by default, it runs last, just so that it can take into account all existing proxies

Asynchronous processing can also be enabled using XML configuration – by using the task namespace:

1
2
<task:executor id="myexecutor" pool-size="5"  />
<task:annotation-driven executor="myexecutor"/>

3. The @Async Annotation

First – let’s go over the rules – @Async has two limitations:

  • it must be applied to public methods only
  • self-invocation – calling the async method from within the same class – won’t work

The reasons are simple – the method needs to be public so that it can be proxied. And self-invocation doesn’t work because it bypasses the proxy and calls the underlying method directly.

3.1. Methods with void Return Type

Following is the simple way to configure a method with void return type to run asynchronously:

1
2
3
4
5
@Async
public void asyncMethodWithVoidReturnType() {
    System.out.println("Execute method asynchronously. "
      + Thread.currentThread().getName());
}

3.2. Methods With Return Type

@Async can also be applied to a method with return type – by wrapping the actual return in the Future:

1
2
3
4
5
6
7
8
9
10
11
12
13
@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 also provides an AsyncResult class which implements Future. This can be used to track the result of asynchronous method execution.

Now, let’s invoke the above method and retrieve the result of the asynchronous process using the Future object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
    }
}
 

4. The Executor

By default, Spring uses a SimpleAsyncTaskExecutor to actually run these methods asynchronously. The defaults can be overridden at two levels – at the application level or at the individual method level.

4.1. Override the Executor at the Method Level

The required executor needs to be declared in a configuration class:

1
2
3
4
5
6
7
8
9
@Configuration
@EnableAsync
public class SpringAsyncConfig {
     
    @Bean(name = "threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        return new ThreadPoolTaskExecutor();
    }
}

Then the executor name should be provided as an attribute in @Async:

1
2
3
4
5
@Async("threadPoolTaskExecutor")
public void asyncMethodWithConfiguredExecutor() {
    System.out.println("Execute method with configured executor - "
      + Thread.currentThread().getName());
}

4.2. Override the Executor at the Application Level

The configuration class should implement the AsyncConfigurer interface – which will mean that it has the implement the getAsyncExecutor() method. It’s here that we will return the executor for the entire application – this now becomes the default executor to run methods annotated with @Async:

1
2
3
4
5
6
7
8
9
10
@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
     
    @Override
    public Executor getAsyncExecutor() {
        return new ThreadPoolTaskExecutor();
    }
     
}

5. Exception Handling

When a method return type is a Future, exception handling is easy – Future.get() method will throw the exception.

But, if the return type is voidexceptions will not be propagated to the calling thread. Hence we need to add extra configurations to handle exceptions.

We’ll create a custom async exception handler by implementing AsyncUncaughtExceptionHandler interface. The handleUncaughtException() method is invoked when there are any uncaught asynchronous exceptions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
        }
    }
     
}

In the previous section, we looked at the AsyncConfigurer interface implemented by the configuration class. As part of that, we also need to override the getAsyncUncaughtExceptionHandler() method to return our custom asynchronous exception handler:

1
2
3
4
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    return new CustomAsyncExceptionHandler();
}

6. Conclusion

In this tutorial, we looked at running asynchronous code with Spring. We started with the very basic configuration and annotation to make it work but also looked at more advanced configs such as providing our own executor, or exception handling strategies.

How To Do @Async in Spring--转的更多相关文章

  1. SpringBoot系列:Spring Boot异步调用@Async

    在实际开发中,有时候为了及时处理请求和进行响应,我们可能会多任务同时执行,或者先处理主任务,也就是异步调用,异步调用的实现有很多,例如多线程.定时任务.消息队列等, 这一章节,我们就来讲讲@Async ...

  2. spring boot使用@Async异步注解

    1.java的大部分接口的方法都是串行执行的,但是有些业务场景是不需要同步返回结果的,可以把结果直接返回,具体业务异步执行,也有些业务接口是需要并行获取数据,最后把数据聚合在统一返回给前端. 通常我们 ...

  3. 161021、spring异步调用,完美解决!

    前言 项目中,用户抢单,下单需要向对方推送消息,但是加上推送就会造成抢单和下单性能降低,反应变慢,因为抢单下单动作跟推送部分是同步的,现在想改成异步推送. 在Java应用中,绝大多数情况下都是通过同步 ...

  4. 【Spring】6、注解大全

    一.@interface Java用  @interface Annotation{ } 定义一个注解 @Annotation,一个注解是一个类. 二.@Override,@Deprecated,@S ...

  5. spring 类注入失败,解决之道

    1.今天偶尔发现的问题,如果你在一个类上面用了注解@Async,spring的异步注解之后,发现如果别的类用@Autowired导入这个类时会失败! 解决办法:用了@Async无非是想方便的用异步操作 ...

  6. Java方式配置Spring MVC

    概述 使用Java方式配置Spring MVC,以及回顾一下Spring MVC的各种用法. Spring MVC简述 关于Spring MVC的介绍网上有很多,这里就不再赘述了,只是要说一下,Spr ...

  7. 注解@Async解决异步调用问题

    序言:Spring中@Async 根据Spring的文档说明,默认采用的是单线程的模式的.所以在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的. 那么当多个任务的执行势必会相互影响. ...

  8. springmvc实现long-pulling技术

    背景介绍: 项目中有一个通讯模块,本来是用websocket全双工技术实现的,但IE10下面不支持websocket,而国内的360.2345浏 览器封装的所有是IE10下面的内核,考虑到站点在国内的 ...

  9. servlet3异步原理与实践

    一.什么是Servlet servlet 是基于 Java 的 Web 组件,由容器进行管理,来生成动态内容.像其他基于 Java 的组件技术一样,servlet 也是基于平台无关的 Java 类格式 ...

  10. springboot-async

    在项目中,当访问其他人的接口较慢或者做耗时任务时,不想程序一直卡在耗时任务上,想程序能够并行执行, 我们可以使用多线程来并行的处理任务,也可以使用spring提供的异步处理方式@Async. Spri ...

随机推荐

  1. Java悲观锁和乐观锁

    悲观的并发策略——Synchronized互斥锁 互斥锁是最常见的同步手段,在并发过程中,当多条线程对同一个共享数据竞争时,它保证共享数据同一时刻只能被一条线程使用,其他线程只有等到锁释放后才能重新进 ...

  2. Xcode的一些控制台命令

    命令 解释 break NUM 在指定的行上设置断点 bt 显示所有的调用栈帧,该命令可用来显示函数的调用顺序 clear 删除设置在特定源文件.特定行上的断点,其用法为:clear FILENAME ...

  3. Repeater 中 OnItemCommand 用法

    <table> <asp:Repeater ID="rptList" runat="server"OnItemCommand="rp ...

  4. USACO 保护花朵 Protecting the Flowers, 2007 Jan

    Description 约翰留下了 N 只奶牛呆在家里,自顾自地去干活了,这是非常失策的.他还在的时候,奶牛像 往常一样悠闲地在牧场里吃草.可是当他回来的时候,他看到了一幕惨剧:他的奶牛跑进了他的花园 ...

  5. Web前端必须规避的8个误区

    现在,有越来越多所谓的“教程”来帮助我们提高网站的易用性.下面收集了一些在Web开发中容易出错和被忽略的小问题,并且提供了参考的解决方案,以便于帮助Web开发者更好的完善网站. 通过避免下面这些小错误 ...

  6. javascript动画函数封装

    function animate(obj, target) { clearInterval(obj.timer); obj.timer = setInterval(function () { var ...

  7. Spinner默认选择问题

    1.需求中使用Spinner,不允许有默认选中,在网上查了好多,有设置 spinner.setSelection(-1,true); 也有设置如下: spinner.setOnItemSelected ...

  8. 编码介绍(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)

    转载:http://blog.jobbole.com/30526/(前面内容)和http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf ...

  9. Java之Foreach语句

    Foreach是for语句的特殊简化版本,但任何时候的foreach语句都可以改写成for语句.Foreach语句在遍历数组等方面为程序员提供了很大的方便 语法如下: For(元素变量 x:遍历对象o ...

  10. poj 2828 Buy Tickets【线段树 单点更新】

    倒着插,先不理解意思,后来看一篇题解说模拟一下 手动模拟一下就好理解了----- 不过话说一直写挫---一直改啊----- 好心塞------ #include <cstdio> #inc ...