转载

Spring 异步任务的创建、自定义配置和原理

@EnableAsync@Configuration 类一起使用,如下所示,为整个Spring应用程序上下文启用注释驱动的异步处理

@Configuration
 @EnableAsync
 public class AppConfig {

 }
复制代码

2.2 编写异步任务

@Component
public class EmailService {
    @Async
    //无返回类型
    public void send(String from, String to, String subject, String text) {
        //do send
    }
    
    @Async
    //有返回类型
    public Future<String> send(String from, String to, String subject, String text) {
        System.out.println("Execute method asynchronously - "
         + Thread.currentThread().getName());
        try {
           Thread.sleep(5000);
           return new AsyncResult<String>("hello world !!!!");
        } catch (InterruptedException e) {
           //
        }
    
        return null;
    }
}
复制代码

当我们调用 send() 方法时,这个任务就会异步去执行, @Async 不仅可以用在方法上,还可以用在Bean类上,如果在类所有方法都是异步的

3 自定义Executor

默认情况下,Spring将搜索关联的线程池定义:上下文中的唯一 TaskExecutor bean ,或者另一个名为“taskExecutor”的 Executor bean 。如果两者都不可解析,则将使用 SimpleAsyncTaskExecutor 处理异步方法调用。此外,具有 void 返回类型的带注解的方法不能将任何异常发送回调用者。默认情况下,仅记录下此类未捕获的异常。

要自定义所有这些,需要实现 AsyncConfigurer 并提供:

  • 自定义 Executor : 通过 getAsyncExecutor() 方法实现
  • 自定义 AsyncUncaughtExceptionHandler : 通过 getAsyncUncaughtExceptionHandler() 来实现

注意: AsyncConfigurer 配置类在应用程序上下文引导程序的早期初始化。如果你对其他 bean 有任何依赖,请确保尽可能地声明它们为 Lazy ,以便让它们通过其他后处理器。

@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {

     @Override
     public Executor getAsyncExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         executor.setCorePoolSize(7);
         executor.setMaxPoolSize(42);
         executor.setQueueCapacity(11);
         executor.setThreadNamePrefix("MyExecutor-");
         executor.setWaitForTasksToCompleteOnShutdown(true);//默认是false,即shutdown时会立即停止并终止当前正在执行任务
         executor.setRejectedExecutionHandler((r, executor1) -> {
            for(;;) {
                try {
                    executor1.getQueue().put(r);
                } catch (InterruptedException e) {
                    e.printStackTrace();

                }
                return;
            }
        });//指定被拒绝任务的处理方法,经过测试当并发量超过队列长度时可以继续执行,否则会抛出 org.springframework.core.task.TaskRejectedException异常
         executor.initialize();
         return executor;
     }
    
     @Override
     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return new CustomAsyncExceptionHandler();//自定义未捕获异常处理,参考 4 异常处理 小节
     }
}
复制代码

3.1 在方法级别自定义Executor

以上为应用级别重写Executor,Spring还提供方法级别重写: 开启Async并自定义Executor:

@Configuration
@EnableAsync
public class SpringAsyncConfig {
    
   @Bean(name = "threadPoolTaskExecutor")
   public Executor threadPoolTaskExecutor() {
       return new ThreadPoolTaskExecutor();
   }
}
复制代码

使用自定义Executor

@Async("threadPoolTaskExecutor")
public void asyncMethodWithConfiguredExecutor() {
    System.out.println("Execute method with configured executor - "
      + Thread.currentThread().getName());
}
复制代码

4 异常处理

当方法返回类型是 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);
        }
    }
     
}
复制代码
原文  https://juejin.im/post/5c651ae5e51d450164637c71
正文到此结束
Loading...