spring 使用@Async注解实现异步执行

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中异步执行代码。首先了解基本配置和注解方法异步执行,也涉及高级配置——配置不同级别的执行器和异常处理策略。

猜你喜欢

转载自blog.csdn.net/neweastsun/article/details/80919415