web-dev-qa-db-fra.com

Spring @Async avec CompletableFuture

J'ai un doute sur ce code:

@Async
public CompletableFuture<String> doFoo() {
    CompletableFuture<String> fooFuture = new CompletableFuture<>();  

    try {
        String fooResult = longOp();
        fooFuture.complete(fooResult);
    } catch (Exception e) {
        fooFuture.completeExceptionally(e);
    }

    return fooFuture;
}

La question est: doFoo ne retourne-t-il fooFuture qu'après la fin de longOp (correctement ou exceptionnellement) et retourne donc des futurs déjà terminés ou Spring fait-il de la magie et revient-il avant d'exécuter le corps? Si le code bloque sur longOp (), comment exprimeriez-vous que le calcul est transmis à un exécuteur?

Peut-être cela? De toute autre manière?

@Async
public CompletableFuture<String> doFoo() {

    CompletableFuture<String> completableFuture = new CompletableFuture<>();
    CompletableFuture.runAsync(() -> {
        try {
            String fooResult = longOp();
            completableFuture.complete(fooResult);
        } catch (Exception e) {
            completableFuture.completeExceptionally(e);
        }
    });
    return completableFuture;
}
14
Eddy

Spring fait en fait tout le travail derrière les couvertures, vous n'avez donc pas à créer le CompletableFuture vous-même. Fondamentalement, l'ajout de @Async l'annotation est comme si vous appeliez votre méthode d'origine (sans l'annotation) comme:

CompletableFuture<User> future = CompletableFuture.runAsync(() -> doFoo());

Quant à votre deuxième question, afin de la transmettre à un exécuteur, vous pouvez spécifier le nom du bean exécuteur dans le valeur du @Async annotation, comme ceci:

    @Async("myExecutor")
    public CompletableFuture<User> findUser(String usernameString) throws InterruptedException {
        User fooResult = longOp(usernameString);
        return CompletableFuture.completedFuture(fooResult);
    }

Ce qui précède serait fondamentalement le suivant comme si vous appeliez votre méthode d'origine, comme:

CompletableFuture<User> future = CompletableFuture.runAsync(() -> doFoo(), myExecutor);

Et toute votre logique exceptionally que vous feriez avec le CompletableFuture renvoyé de cette méthode.

19
Dovmo