Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Async with CompletableFuture

I have a doubt about this 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;
}

The question is: does doFoo return fooFuture only after longOp has finished (either correctly or exceptionally) and is therefore returning already completed futures or is Spring doing some magic and returning before executing the body? If the code is blocking on longOp(), how would you express that the computation is being fed to an executor?

Perhaps this? Any other way?

@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;
}
like image 233
Eddy Avatar asked Nov 17 '17 13:11

Eddy


People also ask

What is @async in Spring?

The @EnableAsync annotation switches on Spring's ability to run @Async methods in a background thread pool. This class also customizes the Executor by defining a new bean. Here, the method is named taskExecutor , since this is the specific method name for which Spring searches.

What is the use of @async in Spring boot?

Here @EnableAsync is used for enabling asynchronous processing with Java Spring Boot Configuration and switches Spring's ability to run @Async methods. The @Async Methods run in the background thread pool without interruption other parallel processes.

What is CompletableFuture in Spring?

public class CompletableFuture<T> extends Object implements Future<T>, CompletionStage<T> A Future that may be explicitly completed (setting its value and status), and may be used as a CompletionStage , supporting dependent functions and actions that trigger upon its completion.

Can we use @async on private method?

Never use @Async on top of a private method. In runtime, it will not able to create a proxy and, therefore, not work.


1 Answers

Spring actually does all of the work behind the covers so you don't have to create the CompletableFuture yourself. Basically, adding the @Async annotation is as if you called your original method (without the annotation) like:

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

As for your second question, in order to feed it to an executor, you can specify the exectutor bean name in the value of the @Async annotation, like so:

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

The above would basically be the following as if you called your original method, like:

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

And all of your exceptionally logic you would do with the returned CompletableFuture from that method.

like image 190
Dovmo Avatar answered Oct 15 '22 01:10

Dovmo