Spring Boot — это популярная среда разработки Java, предоставляющая богатый набор функций и удобную настройку, позволяющую разработчикам больше сосредоточиться на бизнес-логике. Что касается асинхронного программирования, Spring Bootпредоставил@Async
аннотация,Это позволяет выполнить метод асинхронно.,Улучшите производительность параллельной работы системы. Однако,в использовании@Async
аннотациячас,Есть некоторые потенциальные подводные камни, о которых следует знать。В этой статье будет подробно рассмотреноSpring Bootиспользуется в@Async
аннотациячасможет столкнутьсяиз8большие ловушки,и предложить соответствующие решения.
в использовании@Async
аннотация До,Должно быть весной BootВ основной класс конфигурации приложения добавьте@EnableAsync
аннотация,чтобы включить поддержку асинхронного метода. Если вы проигнорируете этот шаг,@Async
аннотацияне вступит в силу。
@SpringBootApplication
@EnableAsync
public class YourApplication {
public static void main(String[] args) {
SpringApplication.run(YourApplication.class, args);
}
}
одеяло@Async
аннотация Изменитьизметодне может быть напрямуюодеялотот же класссерединаиздругойметодвызов。потому чтоSpringбудет работатьчас Создать прокси-класс,При вызове асинхронного метода вы фактически вызываете метод этого прокси-класса. поэтому,Если вы вызываете асинхронный метод непосредственно в том же классе,@Async
аннотацияне вступит в силу。
@Service
public class YourService {
@Async
public void asyncMethod() {
// асинхронная логика выполнения
}
public void callingAsyncMethod() {
// Прямой вызов asyncMethod не будет выполнен.
asyncMethod();
}
}
Решение состоит в том, чтобы ввести инъекциюYourService
прокси-объект для вызоваасинхронныйметод。
@Service
public class YourService {
@Autowired
private YourService self;
@Async
public void asyncMethod() {
// асинхронная логика выполнения
}
public void callingAsyncMethod() {
// Вызов асинхронного метода через прокси-объект
self.asyncMethod();
}
}
Если в том же классе асинхронный метод вызывает другой асинхронный метод, также возникнет проблема с асинхронным выполнением. Это связано с тем, что Spring использует AOP на основе прокси-сервера для реализации асинхронных методов по умолчанию, а вызовы методов внутри прокси-объекта не запускают перехват AOP.
@Service
public class YourService {
@Async
public void asyncMethod1() {
// асинхронная логика выполнения
}
@Async
public void asyncMethod2() {
// асинхронная логика выполнения
asyncMethod1(); // Этот вызов не будет выполнен
}
}
Решение состоит в том, чтобы получить текущий прокси-объект через AopContext.currentProxy() и затем вызвать асинхронный метод.
@Service
public class YourService {
@Autowired
private YourService self;
@Async
public void asyncMethod1() {
// асинхронная логика выполнения
}
@Async
public void asyncMethod2() {
// асинхронная логика выполнения
self.asyncMethod1(); // Выполнить асинхронно через вызов прокси-объекта
}
}
Если вы используете@Async
аннотацияизасинхронныйметодиз Возвращаемое значениеvoid
,Тогда исключение, созданное в этом методе, не будет перехвачено. Это связано с тем, что исключения не могут передаваться между потоком, вызывающим асинхронный метод, и потоком, который фактически выполняет асинхронный метод.
@Service
public class YourService {
@Async
public void asyncMethod() {
// асинхронная логика выполнения
throw new RuntimeException("Async method exception");
}
}
Решение состоит в том, чтобы установить возвращаемое значениеFuture
,Таким образом вы можете позвонитьget()
методчас Исключение поймано。
@Service
public class YourService {
@Async
public Future<Void> asyncMethod() {
// асинхронная логика выполнения
throw new RuntimeException("Async method exception");
}
}
При вызове асинхронного метода,может пройтиFuture
изget()
метод Исключение поймано。
@Service
public class YourService {
@Autowired
private YourService self;
public void callAsyncMethod() {
try {
self.asyncMethod().get();
} catch (Exception e) {
// поймать исключение
}
}
}
Если вызывается непосредственно в том же классе с@Async
аннотацияизметод,Оно не может быть выполнено. Потому что Spring сгенерирует прокси-класс во время выполнения.,Внешние прямые вызовы фактически вызывают методы исходного класса.,Вместо метода прокси-класса.
@Service
public class YourService {
@Async
public void asyncMethod() {
// асинхронная логика выполнения
}
}
@Service
public class AnotherService {
@Autowired
private YourService yourService;
public void callAsyncMethod() {
// внешний Прямой вызов asyncMethod не будет выполнен.
yourService.asyncMethod();
}
}
Решение состоит в том, чтобы ввести инъекциюYourService
прокси-объект для вызоваасинхронныйметод。
@Service
public class YourService {
@Autowired
private YourService self;
@Async
public void asyncMethod() {
// асинхронная логика выполнения
}
}
@Service
public class AnotherService {
@Autowired
private YourService self;
public void callAsyncMethod() {
// Вызов асинхронного метода через прокси-объект
self.asyncMethod();
}
}
@Async
аннотация Только публичнометодэффективный,Поэтому «частное
Метод не может быть выполнен. Если попытаться дать
privateМетод добавлен
@Async`аннотация,не будет иметь никакого эффекта.
@Service
public class YourService {
@Async
private void asyncMethod() {
// @Asyncannotation здесь не вступит в силу
}
}
Решение состоит в том, чтобы извлечь логику, которая будет выполняться асинхронно, в общедоступный метод и вызвать этот общедоступный метод в частном методе.
@Service
public class YourService {
@Async
public void asyncMethod() {
doAsyncMethod();
}
private void doAsyncMethod() {
// асинхронная логика выполнения
}
}
в использовании@Async
аннотациячас,Spring Boot по умолчанию создаст пул потоков для выполнения асинхронного метода. Если не настроено,по умолчаниюиспользоватьиздаSimpleAsyncTaskExecutor
,Это однопоточный исполнитель,Может вызвать узкие места в производительности.
Чтобы решить эту проблему, можно настроить подходящий пул потоков. Вот пример конфигурации:
@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
}
Эта конфигурация используетThreadPoolTaskExecutor
,И установите такие параметры, как количество основных потоков, максимальное количество потоков и емкость очереди.,Внесите коррективы в соответствии с реальными условиями.
по умолчанию,использовать@Async
аннотацияизметод与делада不兼容из。потому чтов использованииделаизметодсерединавызовиспользовать@Async
аннотацияизметодчас,Транзакции не будут распространяться на асинхронные методы.,Асинхронный метод будет выполнен без транзакции.
Решение состоит в том, чтобы@Async
аннотация Добавить в другой классизметодначальство,Асинхронный метод вызывается через прокси-объект.
@Service
public class YourService {
@Autowired
private AsyncService asyncService;
@Transactional
public void transactionalMethod() {
// Вызов асинхронного метода в транзакции
asyncService.asyncMethod();
}
}
@Service
public class AsyncService {
@Async
public void asyncMethod() {
// асинхронная логика выполнения
}
}
Переместив асинхронный метод в другой класс, вы можете гарантировать, что асинхронный метод будет выполняться в новой транзакции и не будет конфликтовать с внешними транзакциями.
использовать@Async
аннотациявозможность улучшить системуиз Производительность параллелизма,нов использованиичас Необходимо знать о некоторых возможностяхизвопрос。проходить Узнайте больше о весне Bootсередина@Async
аннотацияизэтот8большие ловушки,и принять соответствующие решения,Может лучше применять асинхронное программирование,Обеспечить надежность и производительность системы. Надеюсь, эта статья поможет вам понять и использовать Spring Асинхронная аннотация в Boot.