Создание, пользовательская настройка и принцип асинхронных задач Spring

Spring

1 весенняя версия

5.1.4.RELEASE

2 Основное использование

2.1 Включить поддержку асинхронных задач

@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 Пользовательский исполнитель

По умолчанию 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() выдает исключение.

Однако если возвращаемый тип недействителен, исключение не распространяется на вызывающий поток. Поэтому нам нужно добавить дополнительную конфигурацию для обработки исключений.

Мы добьемся путем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);
        }
    }
     
}

5 принципов

В общем, Spring использует технологию АОП для реализации асинхронных задач, и подробные принципы будут описаны позже.

6 Ссылка