x Java Java 8 JUnit JSON
  • XML
  • JDBC Spring Boot Microservices React Contact Us

    Spring Boot Asynchronous Controller example

    As of Servlet 3, it is possible to handle a HTTP request asynchronously by releasing the thread that handles the HTTP request. This is useful when a call takes some time to send the response, so instead of blocking the thread, you can do the processing in the background and return the data when the processing is done by another thread.

    Spring MVC supports following return types that are processed asynchronously : DeferredResult<V>, ListenableFuture<V>, CompletionStage<V>, CompletableFuture<V>, Callable<V>, ResponseBodyEmitter<V>, SeeEmitter<V>, StreamingResponseBody<V>.

    Below example shows how to send the response to a HTTP request asynchronously in a Spring Boot MVC application.

    Step 1) Add below dependency in pom.xml

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

    Step 2) Create AynchronousControllerApplication class

    package com.example.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class AynchronousControllerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(AynchronousControllerApplication.class, args);
        }
    }
            

    Step 3) Create AynchronousController class which will send reponse asynchronously using Callable

    package com.example.demo;
    
    import java.util.concurrent.Callable;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class AynchronousController {
    
        @GetMapping()
        public Callable<String> hello() {
            return () -> {
                Thread.sleep(2000); // simulate time consuming call
                return "Hello Aynchronous Controller";
            };
        }
    }       

    Sending reponse asynchronously from the Controller using CompletableFuture

    package com.example.demo;
    
    import java.util.concurrent.CompletableFuture;
    
    import org.springframework.core.task.TaskExecutor;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class AynchronousController {
        
        private final TaskExecutor taskExecutor; 
        
        public AynchronousController(TaskExecutor taskExecutor) {
            this.taskExecutor = taskExecutor;
        }
    
       @GetMapping()
        public CompletableFuture<String> hello() {
            return CompletableFuture.supplyAsync(() -> {
                delay(2000); // simulate time consuming call
                return "Hello Aynchronous Controller";
            }, taskExecutor );
        }
        
        private void delay(long time) {
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } 
        }
    } 

    Step 4) Running AynchronousControllerApplication

    Console Output :

    2020-01-18 10:55:31.320  INFO 4352 --- [main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.21]
    2020-01-18 10:55:31.648  INFO 4352 --- [main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2020-01-18 10:55:31.648  INFO 4352 --- [main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 8809 ms
    2020-01-18 10:55:32.506  INFO 4352 --- [main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2020-01-18 10:55:33.131  INFO 4352 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    2020-01-18 10:55:33.131  INFO 4352 --- [main] c.e.d.AynchronousControllerApplication   : Started AynchronousControllerApplication in 12.524 seconds (JVM running for 13.742)           

    Step 5) Testing AynchronousControllerApplication

    Open any browser and launch http://localhost:8080. You will see 'Hello Aynchronous Controller' message displayed in the broswer.


    Maven Build












    Note that in the logs below, a new thread (nio-8080-exec-1) is started in the backend to handle the request. Then another thread (task-1) did the actual processing and the reponse was submitted by another thread (nio-8080-exec-4) to the dispatcher servlet.

       
    2021-09-03 11:39:03.992 DEBUG 9284 --- [nio-8080-exec-1] o.apache.coyote.http11.Http11Processor   : Socket: Status in: [OPEN_READ], State out: [LONG]
    2021-09-03 11:39:03.992 DEBUG 9284 --- [nio-8080-exec-1] o.apache.coyote.http11.Http11Processor   : State after async post processing: [LONG]
    2021-09-03 11:39:05.999 DEBUG 9284 --- [task-1] o.s.w.c.request.async.WebAsyncManager : Async result set, dispatch to /
    2021-09-03 11:39:06.000 DEBUG 9284 --- [task-1] o.apache.catalina.core.AsyncContextImpl : Req: 503167fb  CReq: 5ef6938d  
    RP: 449c882f  Stage: 7  Thread:               task-1  State:                  N/A  Method: dispatch     URI: /
    2021-09-03 11:39:06.219 DEBUG 9284 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
    

    Comments

    Leave a Reply

    Your email address will not be published. Required fields are marked *











    Share This