So machen Sie @Async im Frühjahr

1. Übersicht

In diesem Artikel werden wir die Unterstützung für asynchrone Ausführung im Frühjahr und die @ Async- Annotation untersuchen.

Einfach ausgedrückt: Wenn Sie eine Bean-Methode mit @Async kommentieren, wird sie in einem separaten Thread ausgeführt, dh der Aufrufer wartet nicht auf den Abschluss der aufgerufenen Methode.

Ein interessanter Aspekt im Frühjahr ist, dass die Ereignisunterstützung im Framework auch die asynchrone Verarbeitung unterstützt, wenn Sie diesen Weg gehen möchten.

2. Aktivieren Sie die Async-Unterstützung

Beginnen wir mit der Aktivierung der asynchronen Verarbeitung mit Java-Konfiguration - indem wir einfach @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:

  • Anmerkung - b y standardmäßig @EnableAsync erkennt Spring @Async Annotation und die EJB 3.1 javax.ejb.Asynchronous ; Mit dieser Option können auch andere benutzerdefinierte Anmerkungstypen erkannt werden
  • Modus - Gibt die Art der Beratung an , die verwendet werden soll - JDK-Proxy-basiertes oder AspectJ-Weben
  • proxyTargetClass - gibt den Proxy- Typ an, der verwendet werden soll - CGLIB oder JDK; Dieses Attribut wird nur wirksam, wenn der Modus auf AdviceMode.PROXY eingestellt ist
  • order - Legt die Reihenfolge fest, in der AsyncAnnotationBeanPostProcessor angewendet werden soll. Standardmäßig wird es zuletzt ausgeführt, damit alle vorhandenen Proxys berücksichtigt werden können

Die asynchrone Verarbeitung kann auch mithilfe der XML-Konfiguration aktiviert werden - mithilfe des Task- Namespace:

3. Die @ Async- Anmerkung

Erstens - lassen Sie uns die Regeln durchgehen - @Async hat zwei Einschränkungen:

  • Es darf nur auf öffentliche Methoden angewendet werden
  • Selbstaufruf - Aufrufen der asynchronen Methode aus derselben Klasse - funktioniert nicht

Die Gründe sind einfach: Die Methode muss öffentlich sein, damit sie als Proxy verwendet werden kann. Der Selbstaufruf funktioniert nicht, da er den Proxy umgeht und die zugrunde liegende Methode direkt aufruft.

3.1. Methoden mit ungültigem Rückgabetyp

Im Folgenden finden Sie die einfache Möglichkeit, eine Methode mit dem Rückgabetyp void so zu konfigurieren, dass sie asynchron ausgeführt wird:

@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 eine AsyncResult- Klasse, die Future implementiert . Dies kann verwendet werden, um das Ergebnis der asynchronen Methodenausführung zu verfolgen.

Rufen wir nun die obige Methode auf und rufen das Ergebnis des asynchronen Prozesses mit dem Future- Objekt ab.

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 Executor

Standardmäßig verwendet Spring einen SimpleAsyncTaskExecutor , um diese Methoden tatsächlich asynchron auszuführen. Die Standardeinstellungen können auf zwei Ebenen überschrieben werden - auf Anwendungsebene oder auf der 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 in @Async als Attribut 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 AsyncConfigurer- Schnittstelle implementieren. Dies bedeutet, dass die Methode getAsyncExecutor () implementiert ist . 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 kommentiert sind :

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

5. Ausnahmebehandlung

Wenn ein Methodenrückgabetyp ein Future ist , ist die Ausnahmebehandlung einfach - die Future.get () -Methode löst die Ausnahme aus.

Wenn der Rückgabetyp jedoch ungültig ist , werden Ausnahmen nicht an den aufrufenden Thread weitergegeben . Daher müssen wir zusätzliche Konfigurationen hinzufügen, um Ausnahmen zu behandeln.

Wir erstellen einen benutzerdefinierten Async-Ausnahmebehandler, indem wir die AsyncUncaughtExceptionHandler- Schnittstelle implementieren . Die handleUncaughtException () -Methode 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 implementierte AsyncConfigurer- Schnittstelle angesehen. Als Teil davon müssen wir auch die Methode getAsyncUncaughtExceptionHandler () überschreiben , um unseren benutzerdefinierten asynchronen Ausnahmebehandler zurückzugeben:

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

6. Fazit

In diesem Tutorial haben wir uns mit der Ausführung von asynchronem Code mit Spring befasst . Wir haben mit der sehr grundlegenden Konfiguration und Annotation begonnen, damit es funktioniert, haben uns aber auch fortgeschrittenere Konfigurationen angesehen, z. B. die Bereitstellung eines eigenen Executors oder Strategien zur Ausnahmebehandlung.

Und wie immer ist der vollständige Code in diesem Artikel auf Github verfügbar.