Spring Boot Async

Spring Boot Async

Using @Async annotation to create asynchronous methods

Today we talk about how to use the annotation @Async of Spring Boot to create method asynchronous in our applications.

Using asynchronous methods allows you to execute tasks that require much time to finish without waiting.

Environment

  • Java 11
  • Spring Boot 7.0.1
  • Maven 3.8.6

Preparing a Method

In this example, we used a method called processDelay that executes a random delay time from 0 to 1500 milliseconds. This method looks like this:

public void processDelay() throws InterruptedException {
      long delay = ThreadLocalRandom.current().nextLong(0, 1500 + 1);
      log.info("processing delay: {}", delay);
      Thread.sleep(delay);
      log.info("delay time processed");

}

The sentence Thread.sleep(delay); is the apply the delay time and the sentence long delay = ThreadLocalRandom.current().nextLong(0, 1500 + 1); get a random long number from 0 to 1500 to indicate the first one the time to wait.

Using @Async

With this annotation we can convert a simple method into an asynchronous method, in our example we will convert processDelay method to an asynchronous one, we only need to add the annotation @Async at the top of our method, like this:

@Async
public void processDelay() throws InterruptedException {
    long delay = ThreadLocalRandom.current().nextLong(0, 1500 + 1);
    log.info("processing delay: {}", delay);
    Thread.sleep(delay);
    log.info("delay time processed");
}

Enabling Async

To can use @Async annotation also we need to active the Spring Boot features async, for do that, we need to add the annotation @EnableAsync, this one should be added to a class, I prefer to include it on the main class.

Example:

@SpringBootApplication
@EnableAsync
public class AsyncApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApplication.class, args);
    }
}

Testing

To validate the async method we will use a @RestController to call our method and pass it how many executions to apply the method, this is our controller example:

@RestController
@Slf4j
public class DelayController implements IDelayController {

    private final IAsyncProcessorService asyncProcessorService;

    public DelayController(IAsyncProcessorService asyncProcessorService){
        this.asyncProcessorService = asyncProcessorService;
    }

    @Override
    @GetMapping(value = "delay/{executions}")
    public void processDelayTime(@PathVariable(value = "executions") int executions) throws InterruptedException {
        log.info("Tries: {}", executions);
        for(int i = 0; i < executions; i++) {
            this.asyncProcessorService.processDelay();
        }
    }
}

now, if we run the application and request our controller, we can see how the method is executed as a background task.

022-11-07 22:14:08.958  INFO 35748 --- [nio-8080-exec-2] c.h.l.c.implementations.DelayController  : Tries: 2
2022-11-07 22:14:08.968  INFO 35748 --- [         task-2] c.h.l.s.i.AsyncProcessorService          : processing delay: 957
2022-11-07 22:14:08.968  INFO 35748 --- [         task-1] c.h.l.s.i.AsyncProcessorService          : processing delay: 263
2022-11-07 22:14:09.249  INFO 35748 --- [         task-1] c.h.l.s.i.AsyncProcessorService          : delay time processed
2022-11-07 22:14:09.926  INFO 35748 --- [         task-2] c.h.l.s.i.AsyncProcessorService          : delay time processed
2022-11-07 22:14:15.184  INFO 35748 --- [nio-8080-exec-3] c.h.l.c.implementations.DelayController  : Tries: 2
2022-11-07 22:14:15.185  INFO 35748 --- [         task-3] c.h.l.s.i.AsyncProcessorService          : processing delay: 403
2022-11-07 22:14:15.185  INFO 35748 --- [         task-4] c.h.l.s.i.AsyncProcessorService          : processing delay: 736
2022-11-07 22:14:15.591  INFO 35748 --- [         task-3] c.h.l.s.i.AsyncProcessorService          : delay time processed
2022-11-07 22:14:15.924  INFO 35748 --- [         task-4] c.h.l.s.i.AsyncProcessorService          : delay time processed

The response is very fast, indicating that the controller is not waiting for the delay, other evidence that the method is executing asynchronously.

image.png

Conclusion

In this post, we can see how to use the Spring Boot @Async annotation to execute methods in background tasks without that we need to wait until the execution finishes.

References