Недавно фанат задал мне вопрос:Он использует его в определенном методе проекта.@Async
аннотация,Но этот метод по-прежнемусинхронный
Выполнено,асинхронный
не работает,В чем причина?
Псевдокод выглядит следующим образом:
@Slf4j
@Service
public class UserService {
@Async
public void async(String value) {
log.info("async:" + value);
}
}
Этот вопрос довольно интересен. Сегодняшняя статья обобщает 9 сценариев, в которых аннотации @Async не работают. Надеюсь, она будет вам полезна.
Чтобы включить функцию асинхронной аннотации @Async в Spring,Необходимо быть в классе запуска проекта.,Или в классе конфигурации,использовать@EnableAsync
аннотация。
Например:
@EnableAsync
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@EnableAsync
аннотация相当于一个выключатель
,Контролируйте, включать ли@Async
аннотацияасинхронныйфункция,По умолчанию выключено.
Если аннотация @EnableAsync не используется в классе запуска проекта, асинхронная функция аннотации @Async не вступит в силу.
В нашем ежедневном развитии,Часто бывает необходимо вызвать из одного метода другой метод.,Например:
@Slf4j
@Service
public class UserService {
public void test() {
async("test");
}
@Async
public void async(String value) {
log.info("async:{}", value);
}
}
В этом примере метод async() вызывается в методе test() класса UserService.
Если объект класса UserService имеет @Autowired в контроллере и вызывается его метод test(), асинхронная функция async() будет недействительна.
Мы знаем, что Spring реализует функцию асинхронности через аннотацию @Async.,Нижний слой на самом деле сквознойSpringизAOP
实现из,То есть нужно пройтиДинамический прокси JDK
илиcglib
,генерироватьпрокси-объект
。
Асинхронная функция добавляется в прокси-объект. Мы должны вызвать метод test() прокси-объекта.
Когда метод вызывается непосредственно внутри класса и метод async() вызывается в методе test(), вызывается асинхронный метод исходного объекта класса, что эквивалентно вызову this.async(). метод, а не метод прокси-класса UserService async().
Поэтому для таких вызовов внутренних методов асинхронная функциональность аннотации @Async будет отключена.
В Java существует 4 типа модификаторов разрешений.
public
:Все классы имеют доступ。private
:Доступен только тому же классу。protected
:тот же класс,Другие классы в том же пакете,Подклассы из разных пакетов имеют доступ.Модификатор по умолчанию
:тот же класс,Другие классы в том же пакете Доступен。В реальной работе мы чаще всего используем общедоступные и частные.
Если я определяю метод в классе Service,Иногда модификаторы разрешений определяются неправильно,Например:
@Slf4j
@Service
public class UserService {
@Async
private void async(String value) {
log.info("async:{}", value);
}
}
В этом примере модификатор разрешения метода async() класса UserService определен как закрытый, поэтому аннотация @Async также станет недействительной.
Потому что приватный модифицированный метод можно использовать только в объектах класса UserService.
Асинхронная функция аннотации @Async требует использования Spring AOP для создания прокси-объекта класса UserService. Прокси-объект не может получить доступ к частному методу класса UserService, поэтому аннотация @Async становится недействительной.
Когда мы пишем новый метод, нам часто необходимо определить возвращаемое значение метода.
Возвращаемое значение может быть void, int, String, User и т. д., но если возвращаемое значение определено неправильно, это также может привести к сбою асинхронной функции аннотации @Async.
Например:
@Service
public class UserService {
@Async
public String async(String value) {
log.info("async:{}", value);
return value;
}
}
Возвращаемое значение асинхронного метода класса UserService — String. Эта ситуация фактически приведет к сбою асинхронной функции аннотации @Async.
В методе ignore() класса AsyncExecutionInterceptor будет вызван метод doSubmit его родительского класса AsyncExecutionAspectSupport. Этот метод является основным кодом асинхронной функции следующим образом:
Как видно из рисунка, возвращаемое значение асинхронного метода, помеченного @Async, равно Future или null.
поэтому,в реальных проектах,Если вы хотите использовать асинхронную функцию аннотации @Async,相关方法из返回值必须是void
илиFuture
。
Иногда наши методы модифицируются как статические, чтобы при вызове мы могли напрямую использовать имя класса.имя метода для доступа к методу.
Но если к методу @Async добавлен модификатор static, например:
@Slf4j
@Service
public class UserService {
@Async
public static void async(String value) {
log.info("async:{}", value);
}
}
В это время асинхронная функция @Async потерпит неудачу, потому что в этом случае идея напрямую сообщит об ошибке: методы, помеченные @Async, должны быть переопределяемыми.
Методы, объявленные с использованием аннотации @Async, должны иметь возможность переопределения. Очевидно, что статические методы являются статическими методами класса и не могут быть переопределены.
Следовательно, в этом случае асинхронная функция аннотации @Async будет недействительна.
Последнее ключевое слово в Java имеет особое значение.
Классы, измененные с помощью Final, не могут быть унаследованы.
Методы, измененные с помощью Final, не могут быть переопределены.
Переменные, измененные с помощью Final, не могут быть изменены.
Если Final используется неправильно,Это также приведет к сбою асинхронной функции аннотации @Async.,Например:
@Slf4j
@Service
public class UserService {
public void test() {
async("test");
}
@Async
public final void async(String value) {
log.info("async:{}", value);
}
}
В этом случае idea также напрямую сообщит об ошибке: методы, помеченные @Async, должны быть переопределяемыми.
Потому что методы, измененные с помощью ключевого слова Final, не могут быть переопределены подклассами.
Следовательно, в этом случае асинхронная функция аннотации @Async будет недействительна.
иногда,Когда мы добавляем новый класс обслуживания,забуду добавить@Service
аннотация,Например:
@Slf4j
//@Service
public class UserService {
@Async
public void async(String value) {
log.info("async:{}", value);
}
}
@Service
public class TestService {
@Autowired
private UserService userService;
public void test() {
userService.async("test");
}
}
В этом случае асинхронная функция аннотации @Async не вступит в силу. Поскольку класс UserService не объявлен с использованием таких аннотаций, как @Service, @Component или @Controller, Spring не будет управлять этим классом, поэтому асинхронные функции Spring использовать нельзя.
В проектах нам часто необходимо создать новый объект, а затем присвоить ему значение или вызвать его метод.
Но если создается новый объект класса обслуживания,Могут возникнуть неожиданные проблемы,Например:
@Slf4j
@Service
public class UserService {
@Async
public void async(String value) {
log.info("async:{}", value);
}
}
@Service
public class TestService {
public void test() {
UserService userService = new UserService();
userService.async("test");
}
}
В методе test() класса TestService создается новый объект класса UserService, а затем вызывается метод async() этого объекта.
Очевидно, что в этом случае метод async() может выполняться только синхронно, а не асинхронно.
Поскольку в проекте наши собственные новые объекты не будут управляться Spring, мы не сможем использовать асинхронную функцию Spring.
Но мы можем пройтиBeanPostProcessor
добрый,Вручную внедрите созданный объект в контейнер Spring.
мыSpring项目中可以использовать@ComponentScan
аннотация指定项目中扫描из包路径,Например:
@ComponentScan({"com.susan.demo.service1"})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Путь com.susan.demo.service1 не существует в проекте, что приведет к сбою асинхронной функции аннотации @Async.
В то же время, если путь, определенный аннотацией @ComponentScan, не включает путь к вашему недавно добавленному классу Servcie, асинхронная функция аннотации @Async также будет недействительной.
最后给大家推荐一下我из技术专栏《100 самых частых вопросов, которые задают программисты》,В нем содержится много подводного опыта.,В последнее время я получил много хороших отзывов.