Как да направя @Async през пролетта

1. Общ преглед

В тази статия ще разгледаме асинхронната поддръжка на изпълнение през пролетта и анотацията @Async .

Просто казано - анотирането на метод на боб с @Async ще го накара да се изпълни в отделна нишка, т.е. повикващият няма да чака завършването на извикания метод.

Един интересен аспект през пролетта е, че поддръжката на събития в рамката също има поддръжка за асинхронна обработка, ако искате да отидете по този маршрут.

2. Активирайте Async Support

Нека започнем с активиране на асинхронна обработка с конфигурация на Java - като просто добавим @EnableAsync към конфигурационен клас:

@Configuration @EnableAsync public class SpringAsyncConfig { ... }

Анотацията за активиране е достатъчна, но както очаквате, има и няколко прости опции за конфигуриране:

  • анотация - по подразбиране @EnableAsync откриваанотация @Async на Spring и EJB 3.1 javax.ejb.Asynchronous ; тази опция може да се използва и за откриване на други, дефинирани от потребителя типове анотации
  • режим - показва вида на съветите, които трябва да се използват - JDK прокси базирани или AspectJ тъкане
  • proxyTargetClass - указва типа прокси, който трябва да се използва - CGLIB или JDK; този атрибут има ефект само ако режимът е зададен на AdviceMode.PROXY
  • order - задава реда, в койтотрябва да се приложи AsyncAnnotationBeanPostProcessor ; по подразбиране той работи последен, само за да може да вземе предвид всички съществуващи прокси

Асинхронната обработка може да бъде активирана и с помощта на XML конфигурация - като се използва пространството от имена на задачата :

3. Анотацията @Async

Първо - нека да разгледаме правилата - @Async има две ограничения:

  • трябва да се прилага само за публични методи
  • самоизвикването - извикването на асинхронния метод от същия клас - няма да работи

Причините са прости - методът трябва да бъде публичен , за да може да бъде прокси. И самоизвикването не работи, защото заобикаля проксито и извиква директно основния метод.

3.1. Методи с тип Void Return

Следва простият начин за конфигуриране на метод с тип void return, който да се изпълнява асинхронно:

@Async public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously. " + Thread.currentThread().getName()); }

3.2. Методи с тип връщане

@Async може да се приложи и към метод с тип връщане - чрез опаковане на действителното връщане в бъдещето:

@Async public Future asyncMethodWithReturnType() { System.out.println("Execute method asynchronously - " + Thread.currentThread().getName()); try { Thread.sleep(5000); return new AsyncResult("hello world !!!!"); } catch (InterruptedException e) { // } return null; }

Spring също осигурява клас AsyncResult, който реализира Future . Това може да се използва за проследяване на резултата от изпълнението на асинхронен метод.

Сега, нека извикаме горния метод и да извлечем резултата от асинхронния процес, използвайки обекта Future .

public void testAsyncAnnotationForMethodsWithReturnType() throws InterruptedException, ExecutionException { System.out.println("Invoking an asynchronous method. " + Thread.currentThread().getName()); Future future = asyncAnnotationExample.asyncMethodWithReturnType(); while (true) { if (future.isDone()) { System.out.println("Result from asynchronous process - " + future.get()); break; } System.out.println("Continue doing something else. "); Thread.sleep(1000); } }

4. Изпълнителят

По подразбиране Spring използва SimpleAsyncTaskExecutor за действително изпълнение на тези методи асинхронно. По подразбиране могат да бъдат заменени на две нива - на ниво приложение или на ниво индивидуален метод.

4.1. Заменете изпълнителя на ниво метод

Необходимият изпълнител трябва да бъде деклариран в клас на конфигурация:

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

Тогава името на изпълнителя трябва да бъде предоставено като атрибут в @Async :

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

4.2. Заменете изпълнителя на ниво приложение

Конфигурационният клас трябва да реализира интерфейса AsyncConfigurer - което ще означава, че има внедряване метода getAsyncExecutor () . Тук ще върнем изпълнителя за цялото приложение - това вече се превръща в изпълнител по подразбиране за изпълнение на методи, анотирани с @Async :

@Configuration @EnableAsync public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } }

5. Обработка на изключения

Когато методът на връщане на метод е бъдеще , обработката на изключения е лесна - методът 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); } } }

В предишния раздел разгледахме интерфейса на AsyncConfigurer, реализиран от класа на конфигурацията. Като част от това, ние също трябва да заменим метода getAsyncUncaughtExceptionHandler () , за да върнем нашия потребителски асинхронен манипулатор на изключения:

@Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new CustomAsyncExceptionHandler(); }

6. Заключение

В този урок разгледахме стартирането на асинхронен код с Spring . Започнахме с най-основната конфигурация и анотация, за да работим, но разгледахме и по-усъвършенствани конфигурации, като предоставяне на собствен изпълнител или стратегии за обработка на изключения.

И както винаги, пълният код, представен в тази статия, е достъпен в Github.