So wird @Async im Frühjahr ausgeführt
1. Überblick
In diesem Artikel untersuchen wir die Annotationasynchronous execution support in Spring - und@Async.
Einfach ausgedrückt: Wenn Sie eine Methode einer Bohne mit@Async kommentieren, erhalten Sieexecute in a separate thread, d. H. Der Aufrufer wartet nicht auf den Abschluss der aufgerufenen Methode.
Ein interessanter Aspekt im Frühjahr ist, dass die Ereignisunterstützung im Frameworkalso has support for async processing, wenn Sie diesen Weg gehen möchten.
Weitere Lektüre:
Frühlingsereignisse
Die Grundlagen von Ereignissen im Frühjahr - Erstellen Sie ein einfaches, benutzerdefiniertes Ereignis, veröffentlichen Sie es und bearbeiten Sie es in einem Listener.
Spring Security Context Propagation mit @Async
Ein kurzes Beispiel für die Weitergabe des Spring Security-Kontexts bei Verwendung der @ Async-Annotation
Servlet 3 Async Support mit Spring MVC und Spring Security
Schnelle Einführung in die Unterstützung von Spring Security für asynchrone Anforderungen in Spring MVC.
2. Async-Unterstützung aktivieren __
Beginnen wir mitenabling asynchronous processing mitJava configuration - indem wir einfach die@EnableAsync zu einer Konfigurationsklasse hinzufügen:
@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }
Die Aktivierungsanmerkung reicht aus, aber wie zu erwarten gibt es auch einige einfache Konfigurationsoptionen:
-
*annotation* – by default,@EnableAsync erkennt die Annotation@Asyncvon Spring und die EJB 3,1javax.ejb.Asynchronous; Mit dieser Option können auch andere benutzerdefinierte Anmerkungstypen erkannt werden
-
mode - Gibt den Typ vonadvice an, der verwendet werden soll - JDK-Proxy-basiertes oder AspectJ-Weben
-
proxyTargetClass - gibt den Typ vonproxy an, der verwendet werden soll - CGLIB oder JDK; Dieses Attribut wird nur wirksam, wennmode aufAdviceMode.PROXY gesetzt ist
-
order - legt die Reihenfolge fest, in derAsyncAnnotationBeanPostProcessor angewendet werden soll; Standardmäßig wird es zuletzt ausgeführt, damit alle vorhandenen Proxys berücksichtigt werden können
Die asynchrone Verarbeitung kann auch mitXML configuration aktiviert werden - mithilfe des Namespacetask:
3. Die Annotation@Async
Erstens - lassen Sie uns die Regeln durchgehen -@Async hat zwei Einschränkungen:
-
Es darf nur auf die Methoden vonpublicangewendet werden
-
Selbstaufruf - Aufrufen der asynchronen Methode aus derselben Klasse - funktioniert nicht
Die Gründe sind einfach -the method needs to be public, damit es Proxy sein kann. Undself-invocation doesn’t work, weil es den Proxy umgeht und die zugrunde liegende Methode direkt aufruft.
3.1. Methoden mit ungültigem Rückgabetyp
Im Folgenden wird die einfache Möglichkeit beschrieben, eine Methode mit dem Rückgabetyp void für die asynchrone Ausführung zu konfigurieren:
@Async
public void asyncMethodWithVoidReturnType() {
System.out.println("Execute method asynchronously. "
+ Thread.currentThread().getName());
}
3.2. Methoden mit Rückgabetyp
@Async kann auch auf eine Methode mit dem Rückgabetyp angewendet werden - indem die tatsächliche Rückgabe in die Zukunft eingeschlossen wird:
@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 bietet auch eineAsyncResult-Klasse, dieFuture implementiert. Dies kann verwendet werden, um das Ergebnis der asynchronen Methodenausführung zu verfolgen.
Rufen Sie nun die obige Methode auf und rufen Sie das Ergebnis des asynchronen Prozesses mit dem ObjektFutureab.
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. Der Vollstrecker
Standardmäßig verwendet Spring einSimpleAsyncTaskExecutor, um diese Methoden tatsächlich asynchron auszuführen. Die Standardeinstellungen können auf zwei Ebenen überschrieben werden - auf Anwendungsebene oder auf Ebene der einzelnen Methoden.
4.1. Überschreiben Sie den Executor auf Methodenebene
Der erforderliche Executor muss in einer Konfigurationsklasse deklariert werden:
@Configuration
@EnableAsync
public class SpringAsyncConfig {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
Dann sollte der Executorname als Attribut in@Async angegeben werden:
@Async("threadPoolTaskExecutor")
public void asyncMethodWithConfiguredExecutor() {
System.out.println("Execute method with configured executor - "
+ Thread.currentThread().getName());
}
4.2. Überschreiben Sie den Executor auf Anwendungsebene
Die Konfigurationsklasse sollte die SchnittstelleAsyncConfigurerimplementieren. Dies bedeutet, dass die MethodegetAsyncExecutor()implementiert werden muss. Hier geben wir den Executor für die gesamte Anwendung zurück. Dies ist jetzt der Standard-Executor zum Ausführen von Methoden, die mit@Async versehen sind:
@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return new ThreadPoolTaskExecutor();
}
}
5. Ausnahmebehandlung
Wenn ein MethodenrückgabetypFuture ist, ist die Ausnahmebehandlung einfach -Future.get() Methode löst die Ausnahme aus.
Wenn der Rückgabetyp jedochvoid ist,exceptions will not be propagated to the calling thread. Daher müssen wir zusätzliche Konfigurationen hinzufügen, um Ausnahmen zu behandeln.
Wir erstellen einen benutzerdefinierten asynchronen Ausnahmebehandler, indem wir die Schnittstelle vonAsyncUncaughtExceptionHandlerimplementieren. Die MethodehandleUncaughtException() wird aufgerufen, wenn nicht erfasste asynchrone Ausnahmen vorliegen:
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);
}
}
}
Im vorherigen Abschnitt haben wir uns die von der Konfigurationsklasse implementierteAsyncConfigurer-Schnittstelle angesehen. Als Teil davon müssen wir auch diegetAsyncUncaughtExceptionHandler()-Methode überschreiben, um unseren benutzerdefinierten asynchronen Ausnahmebehandler zurückzugeben:
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
6. Fazit
In diesem Tutorial haben wir unsrunning asynchronous code with Spring angesehen. Wir haben mit der grundlegenden Konfiguration und Annotation begonnen, um dies zu ermöglichen, haben uns aber auch fortgeschrittenere Konfigurationen angesehen, wie die Bereitstellung eines eigenen Executors oder Ausnahmebehandlungsstrategien.
Und wie immer ist der vollständige Code in diesem Artikel inover on Github verfügbar.