Comment faire @Async au printemps

Comment faire @Async au printemps

1. Vue d'ensemble

Dans cet article, nous allons explorer l'annotationasynchronous execution support in Spring - et@Async.

En termes simples - annoter une méthode d'un bean avec@Async le rendraexecute in a separate thread i.e. l'appelant n'attendra pas l'achèvement de la méthode appelée.

Un aspect intéressant de Spring est que l'événement prend en charge dans le frameworkalso has support for async processing si vous souhaitez emprunter cette voie.

Lectures complémentaires:

Événements de printemps

Les bases des événements de Spring - créez un événement simple et personnalisé, publiez-le et gérez-le dans un écouteur.

Read more

Propagation du contexte de sécurité Spring avec @Async

Petit exemple de propagation du contexte Spring Security lors de l'utilisation de l'annotation @Async

Read more

Prise en charge asynchrone de Servlet 3 avec Spring MVC et Spring Security

Introduction rapide à la prise en charge de Spring Security pour les demandes asynchrones dans Spring MVC.

Read more

2. Activer la prise en charge Async __

Commençons parenabling asynchronous processing avecJava configuration - en ajoutant simplement les@EnableAsync à une classe de configuration:

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

L'annotation d'activation est suffisante, mais comme vous vous en doutez, il existe également quelques options simples pour la configuration:

  • *annotation* – by par défaut,@EnableAsync détecte l'annotation@Async de Spring et les EJB 3.1javax.ejb.Asynchronous; cette option peut également être utilisée pour détecter d'autres types d'annotations définis par l'utilisateur

  • mode - indique le type deadvice à utiliser - JDK proxy ou tissage AspectJ

  • proxyTargetClass - indique le type deproxy à utiliser - CGLIB ou JDK; cet attribut n'a d'effet que si lemode est défini surAdviceMode.PROXY

  • order - définit l'ordre dans lequelAsyncAnnotationBeanPostProcessor doit être appliqué; par défaut, il s'exécute en dernier, juste pour pouvoir prendre en compte tous les proxys existants

Le traitement asynchrone peut également être activé en utilisantXML configuration - en utilisant l'espace de nomstask:


3. L'annotation@Async

Tout d'abord - passons en revue les règles -@Async a deux limitations:

  • il doit être appliqué aux méthodespublic uniquement

  • auto-invocation - appeler la méthode async depuis la même classe - ne fonctionnera pas

Les raisons sont simples -the method needs to be public afin qu'il puisse être mandaté. Etself-invocation doesn’t work car il contourne le proxy et appelle directement la méthode sous-jacente.

3.1. Méthodes avec type de retour nul

Voici le moyen simple de configurer une méthode avec un type de retour void pour une exécution asynchrone:

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

3.2. Méthodes avec type de retour

@Async peut également être appliqué à une méthode avec un type de retour - en enveloppant le retour réel dans le futur:

@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 fournit également une classeAsyncResult qui implémenteFuture. Ceci peut être utilisé pour suivre le résultat de l'exécution d'une méthode asynchrone.

Maintenant, appelons la méthode ci-dessus et récupérons le résultat du processus asynchrone à l'aide de l'objetFuture.

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. L'exécuteur

Par défaut, Spring utilise unSimpleAsyncTaskExecutor pour exécuter ces méthodes de manière asynchrone. Les valeurs par défaut peuvent être remplacées à deux niveaux: au niveau de l'application ou au niveau de la méthode.

4.1. Remplacer l'exécuteur au niveau de la méthode

L'exécuteur requis doit être déclaré dans une classe de configuration:

@Configuration
@EnableAsync
public class SpringAsyncConfig {

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

Ensuite, le nom de l'exécuteur doit être fourni en tant qu'attribut dans@Async:

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

4.2. Remplacer l'exécuteur au niveau de l'application

La classe de configuration doit implémenter l'interfaceAsyncConfigurer - ce qui signifie qu'elle a implémenté la méthodegetAsyncExecutor(). C'est ici que nous allons renvoyer l'exécuteur pour l'ensemble de l'application - il devient maintenant l'exécuteur par défaut pour exécuter les méthodes annotées avec@Async:

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        return new ThreadPoolTaskExecutor();
    }

}

5. Gestion des exceptions

Lorsqu'un type de retour de méthode est unFuture, la gestion des exceptions est facile - la méthodeFuture.get() lèvera l'exception.

Mais, si le type de retour estvoid,exceptions will not be propagated to the calling thread. Par conséquent, nous devons ajouter des configurations supplémentaires pour gérer les exceptions.

Nous allons créer un gestionnaire d'exceptions asynchrone personnalisé en implémentant l'interfaceAsyncUncaughtExceptionHandler. La méthodehandleUncaughtException() est appelée lorsqu'il y a des exceptions asynchrones non interceptées:

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);
        }
    }

}

Dans la section précédente, nous avons examiné l'interfaceAsyncConfigurer implémentée par la classe de configuration. Dans ce cadre, nous devons également remplacer la méthodegetAsyncUncaughtExceptionHandler() pour renvoyer notre gestionnaire d'exceptions asynchrone personnalisé:

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

6. Conclusion

Dans ce tutoriel, nous avons examinérunning asynchronous code with Spring. Nous avons commencé par la configuration de base et les annotations pour que cela fonctionne, mais nous avons également examiné des configurations plus avancées telles que fournir notre propre exécuteur ou des stratégies de gestion des exceptions.

Et, comme toujours, le code complet présenté dans cet article est disponibleover on Github.