1. Überblick

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.

Read more

Spring Security Context Propagation mit @Async

Ein kurzes Beispiel für die Weitergabe des Spring Security-Kontexts bei Verwendung der @ Async-Annotation

Read more

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.

Read more

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.