Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What advantage is there to using Spring @Async vs. CompleteableFuture directly?

What's the advantage of using Spring Async vs. Just returning the CompletableFuture on your own?

like image 659
Christian Bongiorno Avatar asked Jun 21 '17 19:06

Christian Bongiorno


People also ask

What is use of @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 will happen if you specify @async over a public method of a Spring bean?

Simply put, annotating a method of a bean with @Async will make it execute in a separate thread. In other words, the caller will not wait for the completion of the called method. One interesting aspect in Spring is that the event support in the framework also has support for async processing if necessary.

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.


2 Answers

There is no “vs.” between the two – these are complementary technologies:

  • CompletableFuture provides a convenient way to chain different stages of asynchronous computation – with more flexibility than Spring's ListenableFuture;
  • @Async provides convenient management of your background tasks and threads, with standard Spring configuration for your executor(s).

But both can be combined (since Spring 4.2). Suppose you want to turn the following method into a background task returning a CompletableFuture:

public String compute() {
    // do something slow
    return "my result";
}

What you have to do:

  • if not already done: configure your application with @EnableAsync and an Executor bean
  • annotate the method with @Async
  • wrap its result into CompletableFuture.completedFuture()
@Async
public CompletableFuture<String> computeAsync() {
    // do something slow - no change to this part
    // note: no need to wrap your code in a lambda/method reference,
    //       no need to bother about executor handling
    return CompletableFuture.completedFuture("my result");
}

As you notice, you don't have to bother about submitting the background task to an executor: Spring takes care of that for you. You only have to wrap the result into into a completed CompletableFuture so that the signature matches what the caller expects.

In fact, this is equivalent to:

@Autowire
private Executor executor;

public CompletableFuture<String> computeAsync() {
    return CompletableFuture.supplyAsync(() -> {
        // do something slow
        return "my result";
    }, executor);
}

but it removes the need to:

  • inject the executor
  • deal with the executor in a supplyAsync() call
  • wrap the logic in a lambda (or extract it to a separate method)
like image 75
Didier L Avatar answered Oct 17 '22 06:10

Didier L


Your application is managed by the container. Since it's discouraged to spawn Threads on you own, you can let the container inject a managed Executor.

@Service
class MyService {
  @Autowired
  private Executor executor;

  public CompletableFuture<?> compute() {
    return CompletableFuture.supplyAsync(() -> /* compute value */, executor);
  }
}
like image 21
Flown Avatar answered Oct 17 '22 06:10

Flown