Async rest api spring boot

Async rest api spring boot DEFAULT

Async REST API Using Spring Boot

In this post, we will look at two of the most fundamental means of communication in the world of software development. Synchronous communication and asynchronous communication. We will then explore the various means of achieving asynchronous communication in applications. And to demonstrate the topic, we will build a fully functional Async REST API using Spring Boot.

Synchronous Communication

Whenever an HTTP client invokes an HTTP endpoint it expects a rather instantaneous response. i.e. it expects the result of request will be available either immediately or within a tolerable time limit (approx. 60 seconds.) If the client doesn’t receive a response within this time the client will usually time-out waiting for response and throw an error. This mode of communication is perfectly fine for any request that needs data which is available quickly ex: a trivial database lookup or some light-weight computation, etc… These requests are known as synchronous requests and in general we refer to it as synchronous client-server communication. In the REST architectural pattern, we typically use synchronous communication.

The dilemma..!

What happens when the submitted request needs a rather long time to process? Ex: submitting a file with payroll information for processing or adding a long list of users in the system with each receiving an email to confirm their account, etc… These requests need minutes to hours depending on the complexity of the systems involved.

Asynchronous Communication

The polling model of asynchronous communication

The communication pattern where a client drops off a job for background processing and walks away with a token to check back (poll) later on the status of the job, is what a typical asynchronous communication looks like. Usually these are long running jobs or long running tasks.

Here the client submits a job by sending a request to the service and it immediately receives a token associated with the submitted job. The service then spawns off another thread to process the submitted job. The client can use the token to check the status of the submitted job over and over again i.e. the client keeps polling the service to keep track of the updates to the submitted job.

Pro’s and Con’s of the polling model of asynchronous communication

As clearly evident, the client is solely responsible for keeping a track of the job status and to fetch the response/output of the job once the job is completed. An immediately noticeable drawback of this mechanism is that clients need to keep polling the service to keep track of submitted jobs and to get its output.

However, this scheme is favourable where the client sits in a network setup where inbound traffic is not allowed whereas there are no restrictions on the amount of outbound traffic. This is the most common network setup in the most usual cases that involve going across the organizational firewall i.e. network admins will allow outbound requests towards the internet however would not allow any inbound requests from the internet. Moreover, in the event of any outage on the client side, the submitted job’s status/output is not lost as the client can resume polling for the jobs that it submitted.

Being the most common model of asynchronous communication, we will focus more on the polling model in this post. However, before we move on, let us also take a look at…

The callback model of asynchronous communication

The communication pattern where a client drops off a job for background processing with a callback URI where it can be informed about the outcome of the job is another variation of asynchronous communication. Usually these are also long running jobs or long running tasks.

Here the client submits a job by sending a request to the service and doesn’t expect anything immediately (except for an HTTP Status 200 or 201.) The service then spawns off another thread to process the submitted job. Once the job is completed, it’s the responsibility of the service to inform the client about the outcome of the job.

Pro’s and Con’s of the callback model of asynchronous communication

Here the client is not responsible for tracking the job status. It can send a request and sit-back, relax and wait for a response to hit it at the specified callback URI. However, it means that the client needs to expose a service end-point and ensure it’s up & available to the service as the callback URI. i.e. the client is no longer a simple client, it’s now a server as well! Therefore any outage on the client side may potentially impact the service if it tries to reach the callback URI and finds it unavailable which may result in a missed callback. There are other mechanisms that can be put in place to overcome these limitations, however, as you can easily see, this starts bloating up the entire schematic resulting in maintenance over-heads. Also the client now needs to be accessible from the service even across organizational firewalls and if needed across the internet.

An application adhering to the polling model of asynchronous communication

We are going to build an application that exposes a RESTful API which offers endpoints that facilitate the polling model of asynchronous communication. Broadly, the app shall provide: an endpoint to submit (POST) a job with a file, an endpoint to poll for (GET) the status of the submitted job, an endpoint to fetch (GET) the response of the submitted job and an endpoint to clear (DELETE) the submitted job and any data associated with it.

We will use Spring Boot to create this application. Spring Boot allows us to quickly churn out fully working Proof-of-Concept applications to demonstrate key objectives. We will limit this post to highlight only those pieces of application as necessary so that you know what to look out for while building for a polling model of asynchronous communication.

The entire working Proof-of-Concept application can be accessed at:

Async configuration

At the heart of the entire asynchronous processing in within Spring Boot, is the thread pool task executor which needs to be configured and exposed as a Spring bean:

Don’t forget to annotate the class with and also which enables Spring’s asynchronous method execution capability.

This configuration is the first foundation for implementing Spring Boot long running tasks.

Async service

Next, we mark as the service method that will accept an input file and a job-id, and it will return a Future handle using a .

Don’t forget to annotate the method with which indicates to Spring that this is an asynchronous method and provides it the executor configuration using bean name . The annotation is the next foundation for implementing Spring Boot long running tasks.

The task is an instance of a . During the processing of the job, it may complete normally or it may fail. We track the completion stage of the task using the methods or for normal completion or failure respectively.

The job itself is fairly trivial. We count the total number of characters in the file and sleep for 100 milliseconds for each character. We also count the total number of vowels in the file. Finally we delete the uploaded file. 

Remember, this can be any real-life, long-running job.

The POST endpoint

We use a regular REST controller with a POST end-point that accepts a .

We use a random UUID as a token to track every incoming request, save the file sent with request to the local disk, kick-off the asynchronous service, put the in an in-memory map and respond to the caller with the token.

The controller itself is a normal Spring Boot REST Controller. However, the service it invokes is an Asynchronous service and hence this scheme is also more commonly referred to as Spring Boot Async REST Controller.

Keeping track of jobs

We need to keep a track of all the jobs that the service is processing so as to be in a position to respond as appropriate to every subsequent request for status or output from clients. To do this, we need an which essentially just wraps a . The limitation of this design is that once our service is killed, all job progress details are lost.

The response

We have a very trivial response structure that has a job-id, status and an output file URI (applicable only for jobs that are completed.) The class extends from to encapsulate the needed data points.

The other endpoints

In our rest controller, we need a GET endpoint where the clients can poll for job status, another GET endpoint using which the clients can retrieve the job output file and optionally a DELETE endpoint that can be leveraged by the clients to inform the service to destroy the job details including any output.


We use file as a standard means of managing our application configuration. The property can be used to control where the uploaded job files and resultant output files need to be stored.

Code download

The entire working Proof-of-Concept application can be accessed at:

Running the application

Being a gradle application, we can leverage gradle-wrapper to run the Spring Boot application. It will start a server bound to and listen on port for incoming connections.

Use your favourite REST client to issue requests and check the output. For the simplistic use-case that it is, can also be used.

POST a new job

As soon as a new job is posted by a client a response is received immediately. Notice the thread name which belongs to Tomcat handling the incoming request…

… however the actual job is executed asynchronously in another thread named

GET job status

GET the status of the posted asynchronous job. Use received as response from posting a new job command as an input to next command

Once the job status is , you can check the location configured by property to inspect the job output file.

GET job output file

GET the output file produced as a result of completion of the posted asynchronous job. Use the received as response from get the status command as an input to next command

DELETE job and output file

You can check the location configured by property to ensure the job output file is really deleted.


This was a short primer on how to get started with the polling model for asynchronous communication. We used Spring Boot to develop an Asynchronous (async) API using a scheme which is more commonly known as Spring Boot async REST controller. However do remember that the controller is a regular REST controller and the service it invokes is an service. In future posts we will explore the other models of asynchronous jobs.

Hope you enjoyed reading the post and got to learn something. If this post helped you in any way, I would be thrilled to hear about it. Please leave a comment, your inputs inspire me to write more. Cheers!


Asynchronous REST service implementation in Spring boot


Multithreading is good for parallel processing in any project. Through this, we can utilize the computing power of the CPU. By default, every application has a different no of threads for different purposes, we can process our own threads by using async annotation as per needs.


In Spring Boot we use an asynchronous mechanism with three quick steps.


1. Enable Async Support in Spring Boot configuration class.



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.


2. We can customize our async executor as per the required number of concurrent threads runs at a time.




The Executor


We can configure this Bean into the Spring Boot starter configuration class.


Spring Boot uses a SimpleAsyncTaskExector to run an async method.


This Executor runs by default and it can be overridden at two levels- at the individual method levels or at the application level.


3. Add @Async Annotation to a service Method for performing thread’s task without interrupting another parallerl process.


Limitation of @Async Annotation 


1. Async Annotation works on only public methods.


2. If you call async methods from within the same class then it won’t work. It means self invocation is prevented with async processing.


3. It works inconsistently if you are using autorun tools like Dev Tool in your project.

We are aJava Development Companythat enables enterprises to streamline operations and drive returns, using next-gen technologies, with our development services. Our services include developing applications for all your ERP needs from CRM, WFM, and HRM to eCommerce, accounting, and wealth management software. We use an extensive tech stack including Javascript, JWS, Springboot, and JUnit to develop end to end customized software for your enterprise. Get in touch with our experts to know more about how you can implement these technologies into your business.





  1. Best plants for florida panhandle
  2. Nashville tv show season 5
  3. 23 an hour after taxes
  4. Nextcare online check in
In this tutorial we will see how to create an asynchronous REST service endpoint using Spring boot application.
Asynchronous service works in a way that it will not block the client request and do the processing in separate thread. When work is complete the response returned to the client so our service will be able to handle more client requests at the same time, compare to synchronous processing model.
Let's understand how it is working in synchronous mode. In such server/client application at server side it has a pool of threads which are serving the request. If a request received by a thread then it will be blocked until it send the response back to client. In this case if processing doesn't take much time it will be able to process it quickly and accept other client requests but there could be one situation when all threads are busy and not able to accept the new client requests.
synchronous communication

To overcome of such problems, asynchronous processing model introduced for REST services. In this processing model, after receiving the request from client it creates a separate worker thread to process the request and request thread becomes available to accept the more requests. Worker thread send the response back to client once it completes the processing.
asynchronous communication

Here we are going to see how to implement asynchronous REST service using Spring boot application, however now JAX-RS 2 also supports asynchronous communication but Spring uses it's own API for REST implementation.

Maven dependencies

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>


First we need to add this annotation on any configuration class or spring boot main class. Configuration classes are those who have the annotation @Configuration. We need this annotation to enable the asynchronous execution capabilities of Spring. Once async is enable Spring will look for the task executor bean and if it is not found then Spring will use SimpleAsyncTaskExecutor to execute the tasks asynchronously.
@EnableAsync public class SpringBootTutorialApplication Task executor is optional but may be useful depending on our requirement as we can tune it as per need. I am putting it here for your reference but it's your choice whether you want to customize it or not. We need to use the @EnableAsync annotation and implement the interface AsyncConfigurer. Below is code for the task executor implementation.
@EnableAsync public class SpringBootTutorialApplication implements AsyncConfigurer{ public static void main(String[] args) {, args); } @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(20); executor.setQueueCapacity(10); executor.setThreadNamePrefix("DemoExecutor-"); executor.initialize(); return executor; } }

Async REST service

Now we need to create the REST service which execute asynchronously using the WebAsyncTask. WebAsyncTask is a Spring class which needs Callable task to get initialized and then this instance we need to return from our REST endpoint.
It comes with various constructor implementation using which we can supply timeout and custom executors also. Also it provides some callback methods which can be executed on success, error or timeout events for this task. See the below code of our REST service.
@RestController public class AsyncRestController { @GetMapping("/hello") public WebAsyncTaskIn above code we have one REST endpoint "/hello" which accepts a name returns the response after 2 seconds. We are returning an instance of WebAsyncTask which is configured to be timeout after 4 seconds. We will test here below 3 scenarios to see the different response for each of the above callback methods.

1. Success response

In this case it returns response in 2 seconds and "onCompletion" callback method is executed. Here in console output we can see that our logic is executed asynchronously and response has return once it was ready to send after 2 seconds.
URL: http://localhost:8080/hello?name=Akshay
Welcome Akshay!Console output:
service start... service end... task execution start... task execution end... onCompletion...

2. Time out response

Since service is not able to send the response before configured timeout, it will time out and callback method for "onTimout" will be executed. In the console output it shows that even though timeout has occurred, it has executed the callback method for onTimout as well as onCompletion.
URL: http://localhost:8080/hello?name=timeout
Request timed out...Console output:
service start... service end... task execution start... onTimeout... onCompletion...

3. Error response

In this case, we generate the manual exception which results in the execution of "onError" callback method. By seeing the console output it is clear that it throws exception and executes two callback methods "onError" and "onCompletion".
URL: http://localhost:8080/hello?name=error
Returns Spring's error page.Console output:
service start... service end... task execution start... java.lang.RuntimeException: Manual exception at runtime .... onError... onCompletion...
@Async in Spring Boot - Code Debugger

How to make a async REST with Spring?

I'm trying to make a small REST using Spring Boot. I've never used Spring and used Java a long time ago (Java 7)!

In the last 2 years I have used only Python and C# (but like I said, I already used Java).

So, now, I'm trying to make a REST using async methods, and checked several examples, but still, I don't understand very well the "correct way" to do this.

Looking at the following documentation:, Java 8 has that I can use with Spring, so, I made the following code:




This code give me the expected output. Then, looking at another documentation (sorry, I lost the link), I see that Spring accept the following code (which give me the expected output too):

Is there a difference between the two methods?

Then, looking at the following guide:, there's a annotation in class. If I include the annotation and create a Bean like the code from last link, my application don't return nothing on endpoint (only a 200 OK response, but with blank body).

So, my rest is async without the annotation? And why when I use , the response body is blank?


Boot async spring rest api

Take advantage of async processes in REST Applications with Java Spring

2. Uploading multiple documents with cancellation feature

Another usage case is uploading multiple documents at once, in order to attach them to an item. The documents might reside on a third-party server, which means uploading can take some time to complete. While waiting, the user can see a loading bar, and be able to cancel the action.

How does this work?

The frontend sends the documents to the backend and receives a process ID. With this process ID, the frontend can cancel the document uploading at any time (upon the user clicking the Cancel button) by doing a cancel call and passing the process ID.

This can only happen because the document uploading is asynchronous in the backend, and the backend can return the process ID before the upload finishes. In order for the documents upload process to support the cancelation, it has to actively check for any cancel actions, and it needs to know when it’s finished.

We therefore get a more complex process that can be started, finished, or canceled. All these process states are kept in an event table that is used by both the frontend and the backend to track its progress and to show a result to the user when finished (successfully or with errors).

Java Asynchronous Programming

Learn to create asynchronous controller methods in Spring framework with the help of and annotations, async thread pool on top of Java framework.

1. Spring @Async rest controller

Spring comes with annotation and can be applied on application classes for asynchronous behavior. This annotation will look for methods marked with annotation and run in background thread pools. The annotated methods can return to hold the result of an asynchronous computation.

To enable async configuration in spring, follow these steps:

  1. Create async thread pool

    @Configuration @EnableAsync public class AsynchConfiguration { @Bean(name = "asyncExecutor") public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3); executor.setMaxPoolSize(3); executor.setQueueCapacity(100); executor.setThreadNamePrefix("AsynchThread-"); executor.initialize(); return executor; } }
  2. @Async controller methods

    Methods which shall run asynchronously, annotate them with annotation and method return type should return

    @Async("asyncExecutor") public CompletableFuture<EmployeeNames> methodOne() throws InterruptedException { //code }
  3. Combine async method results

2. Spring @Async rest controller example

In this demo, we will create an REST API which will fetch data from three (3) remote services asynchronously and when responses from all 3 services is available then aggregate the responses. e.g.

  1. Invoke API
  2. Invoke API
  3. Invoke API
  4. Wait for responses from above services
  5. Aggregate all three API responses and build final response to send back to client

2.1. EmployeeName, EmployeeAddress and EmployeePhone APIs to be accessed async way

package com.howtodoinjava.example.sampleservice.controller; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.howtodoinjava.example.sampleservice.model.EmployeeAddress; import com.howtodoinjava.example.sampleservice.model.EmployeeAddresses; import com.howtodoinjava.example.sampleservice.model.EmployeeName; import com.howtodoinjava.example.sampleservice.model.EmployeeNames; import com.howtodoinjava.example.sampleservice.model.EmployeePhone; @RestController public class EmployeeDataController { private static Logger log = LoggerFactory.getLogger(EmployeeDataController.class); @RequestMapping(value = "/addresses", method = RequestMethod.GET) public EmployeeAddresses getAddresses() {"get addresses Start"); EmployeeAddresses employeeAddressesList = new EmployeeAddresses(); EmployeeAddress employeeAddress1 = new EmployeeAddress(); EmployeeAddress employeeAddress2 = new EmployeeAddress(); List<EmployeeAddress> addressList = new ArrayList<EmployeeAddress>(); { employeeAddress1.setHouseNo("1111"); employeeAddress1.setStreetNo("111"); employeeAddress1.setZipCode("111111"); employeeAddress2.setHouseNo("222"); employeeAddress2.setStreetNo("222"); employeeAddress2.setZipCode("222222"); addressList.add(employeeAddress1); addressList.add(employeeAddress2); employeeAddressesList.setEmployeeAddressList(addressList); } return employeeAddressesList; } @RequestMapping(value = "/phones", method = RequestMethod.GET) public EmployeePhone getPhoneNumbers() {"get phones Start"); EmployeePhone employeePhone = new EmployeePhone(); { ArrayList<String> phoneNumberList = new ArrayList<String>(); phoneNumberList.add("100000"); phoneNumberList.add("200000"); employeePhone.setPhoneNumbers(phoneNumberList); } return employeePhone; } @RequestMapping(value = "/names", method = RequestMethod.GET) public EmployeeNames getEmployeeName() {"get names Start"); EmployeeNames employeeNamesList = new EmployeeNames(); EmployeeName employeeName1 = new EmployeeName(); EmployeeName employeeName2 = new EmployeeName(); List<EmployeeName> employeeList = new ArrayList<EmployeeName>(); { employeeName1.setFirstName("Santa"); employeeName1.setLastName("Singh"); } { employeeName2.setFirstName("Banta"); employeeName2.setLastName("Singh"); } employeeList.add(employeeName1); employeeList.add(employeeName2); employeeNamesList.setEmployeeNameList(employeeList); return employeeNamesList; } }

2.2. Async thread pool configuration

import java.util.concurrent.Executor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration @EnableAsync public class AsyncConfiguration { @Bean(name = "asyncExecutor") public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3); executor.setMaxPoolSize(3); executor.setQueueCapacity(100); executor.setThreadNamePrefix("AsynchThread-"); executor.initialize(); return executor; } }

2.3. Spring @Async controller methods

package com.howtodoinjava.example.async.service; import java.util.concurrent.CompletableFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import com.howtodoinjava.example.async.model.EmployeeAddresses; import com.howtodoinjava.example.async.model.EmployeeNames; import com.howtodoinjava.example.async.model.EmployeePhone; @Service public class AsyncService { private static Logger log = LoggerFactory.getLogger(AsyncService.class); @Autowired private RestTemplate restTemplate; @Bean public RestTemplate restTemplate() { return new RestTemplate(); } @Async("asyncExecutor") public CompletableFuture<EmployeeNames> getEmployeeName() throws InterruptedException {"getEmployeeName starts"); EmployeeNames employeeNameData = restTemplate.getForObject("http://localhost:8080/name", EmployeeNames.class);"employeeNameData, {}", employeeNameData); Thread.sleep(1000L); //Intentional delay"employeeNameData completed"); return CompletableFuture.completedFuture(employeeNameData); } @Async("asyncExecutor") public CompletableFuture<EmployeeAddresses> getEmployeeAddress() throws InterruptedException {"getEmployeeAddress starts"); EmployeeAddresses employeeAddressData = restTemplate.getForObject("http://localhost:8080/address", EmployeeAddresses.class);"employeeAddressData, {}", employeeAddressData); Thread.sleep(1000L); //Intentional delay"employeeAddressData completed"); return CompletableFuture.completedFuture(employeeAddressData); } @Async("asyncExecutor") public CompletableFuture<EmployeePhone> getEmployeePhone() throws InterruptedException {"getEmployeePhone starts"); EmployeePhone employeePhoneData = restTemplate.getForObject("http://localhost:8080/phone", EmployeePhone.class);"employeePhoneData, {}", employeePhoneData); Thread.sleep(1000L); //Intentional delay"employeePhoneData completed"); return CompletableFuture.completedFuture(employeePhoneData); } }

2.4. Call async methods and aggregate results

package com.howtodoinjava.example.async.controller; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.howtodoinjava.example.async.model.EmployeeAddresses; import com.howtodoinjava.example.async.model.EmployeeNames; import com.howtodoinjava.example.async.model.EmployeePhone; import com.howtodoinjava.example.async.service.AsyncService; @RestController public class AsyncController { private static Logger log = LoggerFactory.getLogger(AsyncController.class); @Autowired private AsyncService service; @RequestMapping(value = "/testAsynch", method = RequestMethod.GET) public void testAsynch() throws InterruptedException, ExecutionException {"testAsynch Start"); CompletableFuture<EmployeeAddresses> employeeAddress = service.getEmployeeAddress(); CompletableFuture<EmployeeNames> employeeName = service.getEmployeeName(); CompletableFuture<EmployeePhone> employeePhone = service.getEmployeePhone(); // Wait until they are all done CompletableFuture.allOf(employeeAddress, employeeName, employeePhone).join();"EmployeeAddress--> " + employeeAddress.get());"EmployeeName--> " + employeeName.get());"EmployeePhone--> " + employeePhone.get()); } }

2.5. How to run the demo

Download and start both the applications.

Hit the API: .

Observe the output in console.

2.5.1. With @Aync Enabled
With Aync Enabled
2.5.2. Without Aync Enabled
Without Aync Methods Enabled

Spring Async Service Sourcecode

Employee Data Service Sourcecode

Drop me your questions related to creating spring boot non blocking rest api.

Happy Learning !!


Let us know if you liked the post. That’s the only way we can improve.


You will also like:

Lets learn about Spring Boot @Async annotation and use it to achieve Async (asynchronous) method execution in Spring Boot.

Introduction to @Async annotation

Normally, A program would run from top to bottom. But sometimes, one operation or method may take time and it would cause other methods to wait. In these cases, it makes sense to run few methods parallely when we can. This is also called asynchronous invocation or in short Async.

For example, There may be an API that needs to wait for payment to complete. In this case, If the payment process takes time, The customer won’t get confirmation.

To handle this, we can initiate payment process in a separate thread and then provide an incomplete order details. If the payment fails, the order can still be retried later and marked as SUCCESS or FAIL.

This is where Java shines with its multi threading capabilities. However, maintaining threads is pain to program. For this reason, Spring Boot provides @Async annotation.

Enabling @Async support in Spring Boot

To enable asynchronous processing, You need to add @EnableAsync to a Spring Boot main class. This async annotation is responsible for creating a thread pool executor for methods to run.

Code language:Java(java)

Without Asynchronous methods

To begin with, Let’s write a dummy controller that uses as service with high response time. Without async, the Spring Boot application will run the HTTP requests in single thread.

Code language:Java(java)

Next, We need to write a service that takes some time to do a task. In this case, We deliberately created HelloService to take 10 seconds using sleep. Note that this implementation doesn’t use Async features of Spring Boot.

Code language:Java(java)

At this point, The /hello API endpoint will take at least 10 seconds to respond. We can test that by doing a CURL.

Without @Async, Spring Boot Rest controller takes 10 seconds

It is no surprise that the API took 10007 milliseconds to complete. But the important thing to note here is that the HelloController and HelloService ran on the same thread. We know this because, The response and the console log has the same thread name.

With @Async in Spring Boot

Next, We are going to add the @Async annotation from spring boot to the long running method.

Code language:Java(java)

With this one line change, The rest controller from the spring boot application should complete the API call quickly. So let’s try out this theory.

With @Async, the Spring Boot Rest controller took only 9 milliseconds.

Note that the API only took 10 seconds to complete. While running the API call, if you notice the logs, You can see a log entry after 10 seconds with a different thread name. For our run the processSomethingForLong method printed out the following.

Code language:plaintext(plaintext)

Async methods with Return Types

Previously, The async method only used a void return type. And in my opinion, that is the best way to write self sufficient asynchronous functions. However, If you want to handle the results from an @Async function, you are in luck. Because Spring framework provides out of the box support for these situations using Future type. This is possible by wrapping the result inside of an AsyncResult class.

Code language:Java(java)

To be frank, The following snippet is to let you know that you can handle return types this way. But in real world, No one would want to sleep inside a loop. The ideal approach should be to handle these Future objects in separate @Scheduled functions.

Code language:Java(java)

Configuring Task Executor

The @EnableAsync annotation creates a handly SimpleAsyncTaskExecutor by default. Unfortunately,This implementation has no practical upper limit for its thread pool size. This means that The Spring boot application may crash if there were too many @Async methods running at the same time. To avoid this , we need to provide our own Executor. And let’s see how.

Spring Boot auto-configuration looks for an AsyncConfigurer which could supply an Executor. By extending this interface, We can supply an implementation of AsyncUncaughtExceptionHandler that handles exceptions from Async tasks.

Code language:Java(java)

If you don’t want to handle any exceptions, You are good with just defining a bean of type Executor. As long as there is only one Bean of this type, you are good to go.

Code language:Java(java)

Multiple Async Executors in Spring Boot

In some cases, few operations are important than others. For example, You may need to process the payments and deliveries in different thread groups so that you can assign more threads to payment and less to deliveries. In this case, you need to map the executor beans using the @Async annotation.

For instance, let’s define two executor beans.

Code language:CSS(css)

We can now map these to different service methods as shown below.

Code language:Java(java)

As you see, This approach lets you define worker processes depending on the type of requests you get.


To summarize, We learned what @Async annotation is for in Spring Boot and how to use and customize them. The following posts about might interest you.


339 340 341 342 343