Spring中如何使用@Async

1.概述

Spring对异步执行的支持和@Async注解的使用。

用@Async注释bean的方法将使它在单独的线程中执行。 换句话说,调用者将不等待被调用方法的完成。

Spring中一个有趣的方面是,框架中的事件支持在必要时也支持异步处理。

2.启用异步支持

首先通过Java配置启用异步处理。

通过将@EnableAsync添加到配置类中来完成此操作:

@Configuration
@EnableAsync
public class SpringAsyncConfig {
    
     

}

启用注解就足够了。 还有一些奇特的配置选项:

  • annotation 默认情况下,@EnableAsync检测Spring的@Async注解和EJB 3.1 javax.ejb.Asynchronous。 也可以使用此选项来检测其他用户定义的注释类型。

  • mode 指示应使用的建议类型-基于JDK代理或AspectJ编织。

    指示应如何应用异步建议。
    默认值为AdviceMode.PROXY。 请注意,代理模式仅允许通过代理拦截呼叫。 同一类内的本地调用无法以这种方式被拦截; 在本地调用中,此类方法上的Async注释将被忽略,因为Spring的拦截器甚至不会在这种运行时场景中起作用。 有关更高级的拦截模式,请考虑将其切换为AdviceMode.ASPECTJ。

  • proxyTargetClass 指示应使用的代理类型-CGLIB或JDK。 仅当模式设置为AdviceMode.PROXY时,此属性才有效。

  • order 设置应用AsyncAnnotationBeanPostProcessor的顺序。 默认情况下,它最后运行,以便可以考虑所有现有代理。

3. @Async注解

@Async有两个限制:

  • 它只能应用于公共方法。
  • 自我调用(从同一类中调用async方法)将无法正常使用。

原因很简单:该方法需要公开,才能被代理。 而且自调用不起作用,因为它绕过了代理并直接调用了底层方法。

3.1.无返回类型的方法

这是配置具有void返回类型的方法以异步运行的简单方法:

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

3.2.带返回值的方法

通过在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类。 可以使用它来跟踪异步方法执行的结果。

单元测试

public void test()
  throws InterruptedException, ExecutionException {
    
    
    System.out.println("Invoking an asynchronous method. " 
      + Thread.currentThread().getName());
    Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();
    //while循环一直等待执行结果
    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.执行器

默认情况下,Spring使用SimpleAsyncTaskExecutor步运行这些方法。 但是我们可以在两个级别上覆盖默认值:应用程序级别或单个方法级别。

4.1.在方法级别覆盖执行器

需要在配置类中声明所需的执行程序:

@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());
}

4.2.在应用程序级别覆盖执行程序

配置类应实现AsyncConfigurer接口。 因此,它必须实现getAsyncExecutor()方法。 在这里,将返回整个应用程序的执行器。 现在,它成为运行以@Async注释的方法的默认执行程序:

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
    
    
    
    @Override
    public Executor getAsyncExecutor() {
    
    
        return new ThreadPoolTaskExecutor();
    }
    
}

5.异常处理

当方法返回类型为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();
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/niugang0920/article/details/116752187