Spring позволяет выполнять методы асинхронно с помощью аннотации @Async. Это один из самых простых способов разгрузить основной поток и не блокировать выполнение.
🔧 Как включить
Добавь @EnableAsync на конфигурационный класс (или на @SpringBootApplication). Без этого @Async работать не будет:
@EnableAsync
@SpringBootApplication
public class App { ... }
Затем помечаешь нужный метод:
@Async
public void sendEmail(String to) {
// выполнится в отдельном потоке
}
🔍 Что под капотом
Spring создаёт AOP-прокси вокруг бина. При вызове @Async-метода прокси перехватывает вызов и отправляет задачу в TaskExecutor (по умолчанию — SimpleAsyncTaskExecutor, который создаёт новый поток на каждый вызов).
Шаги:
1. Вызов метода перехватывается прокси (AsyncExecutionInterceptor)
2. Метод оборачивается в Callable / Runnable
3. Задача отправляется в Executor
4. Вызывающий поток сразу получает управление обратно
📦 Возвращаемые типы
▪️ void
▪️ Future<T>
▪️ CompletableFuture<T>
⚙️ Свой Executor
SimpleAsyncTaskExecutor — плохой выбор для прода, т.к. не переиспользует потоки. Настрой пул:
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("async-");
executor.initialize();
return executor;
}
Или укажи конкретный executor прямо в аннотации:
@Async("taskExecutor")
public void process() { ... }⚠️ Нюансы
— @Async не работает при вызове метода внутри того же класса (та же проблема, что с @Transactional)
— Метод должен быть public
— Исключения из void-методов тихо проглатываются — нужно настроить AsyncUncaughtExceptionHandler
— При CompletableFuture исключение попадёт в объект и его можно обработать через .exceptionally(...)
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise