Part 5 – Asynchronous processing in Spring with @Async and @EnableAsync

What have we learned so far,

Part 1 – Spring Rest Advance : Input / Bean Validations In this post, we discussed the steps to validate the input bean in Spring Rest.
Part 2 – Spring Rest Advance : Rest Documentation with Swagger 2 In this post, we discussed the steps to configure swagger to do the documentation for Spring Rest services
Part 3 – Spring Rest Advance : Spring Boot with H2 DB In this post, we discussed the steps to configure and use H2 db in spring boot
Part 4 – Spring Rest Advance : Spring Rest Versioning In this post we discussed the different ways to do the Rest versioning.

How To Do @Async in Spring Service

Context Consider a situation when you need to create a resource or update a resource and the operation takes long time to complete. Actually, this scenario is not that uncommon: after all, REST is not about manipulation of a couple of database rows in some CRUD scenarios but REST is about manipulation of arbitrary resources, and a resource might require extensive computation in order to come to existence. So, you basically have two options: you will force API client to wait until the resource is actually created you can immediately return some status response, and defer creation to some later point

Why waiting is not cool in Spring

Well, because! More seriously, there’s nothing wrong with forcing API client to wait. If on server side you rely on some code which takes more time to complete then your server will be busy for all the request to complete the execution of this code block and send the response which will eventually degrade the performance of your server and will take more time for the client to respond. It is not unusual that your web service needs to communicate with another web service do some heavy operation in order to serve its clients. In the old days, that would imply that an incoming request to your server would capture one servlet connection, and perform a blocking call to the remote service before it can send a response to the client. It works, but it does not scale very well if you have multiple concurrent clients.

What is the need of Asynchronous?

We can send the immediate response to the client and defer the execution later on the server. In this approach we speed up the server and client interaction and executes the remaining processing in an asynchronous way where a new thread is created to handle the execution. With Asynchronous code we defer the execution part in another thread and close the incoming HTTP rest connection by responding back. Let see how we can achieve this type of processing in Spring Rest. Scenario Suppose we have a resource called /employees which creates the employee on HTTP POST call. The creation of employee resource is time consuming as it requires to perform below two steps : 1. validate and save employee object into database 2. send an email to that employee In these two operation the second operation of sending an email takes time. Lets write code to understand it more clarly : Lets create a EmployeeController
package com.onlyfullstack.springasyncexample.controller;

import com.onlyfullstack.springasyncexample.datatransferobject.EmployeeDTO;
import com.onlyfullstack.springasyncexample.domainobject.EmployeeDO;
import com.onlyfullstack.springasyncexample.exception.EntityNotFoundException;
import com.onlyfullstack.springasyncexample.service.EmailService;
import com.onlyfullstack.springasyncexample.service.EmployeeService;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("employees")
public class EmployeeController {
 
 @Autowired
 private EmployeeService service;

 @Autowired
 private EmailService emailService;
 
 @Autowired
 private ModelMapper mapper;
  
  @PostMapping
  public ResponseEntity<Object> addEmployee(@Valid @RequestBody EmployeeDTO employeeDTO) {
   System.out.println("Entered in addEmployee with : "+employeeDTO);
   EmployeeDO employeeDO = mapper.map(employeeDTO, EmployeeDO.class);
   service.addEmployee(employeeDO);
   System.out.println("Employee saved into database");
   emailService.sendMail(employeeDO.getEmail());
   System.out.println("Exited from addEmployee");
   return new ResponseEntity<>(HttpStatus.CREATED);
  }

}
EmployeeSerice
package com.onlyfullstack.springasyncexample.service;

import com.onlyfullstack.springasyncexample.domainobject.EmployeeDO;
import com.onlyfullstack.springasyncexample.exception.EntityNotFoundException;
import com.onlyfullstack.springasyncexample.repositoy.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class EmployeeServiceImpl implements EmployeeService{

 @Autowired
 private EmployeeRepository repository;
 
 @Override
 public void addEmployee(EmployeeDO employee) {
  repository.save(employee);
 }
}
EmailService – Lets add thread sleep of 5 seconds to simulate the sendMail takes sometime.
package com.onlyfullstack.springasyncexample.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class EmailService {

    public void sendMail(String email) {
        System.out.println("Entered in sendMail with mailId : " + email);
        try {
            int seconds = 5;
            for (int i = 1; i <= 5; i++) {
                System.out.println("Wating for "+seconds+" seconds" );
                Thread.sleep(1000);
                seconds --;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Exited from sendMail");
    }
}
We are ready with our code. Lets run it and fire the HTTP POST with below data. Url : http://localhost:8088/employees data : { “firstName”: “only”, “lastName”: “fullstack”, “salary”: 1000, “email” : “saurabh@e.com” } Selection 006 Output in console Entered in addEmployee with : EmployeeDTO(id=null, firstName=only, lastName=fullstack, salary=1000, email=saurabh@e.com) Employee saved into database Entered in sendMail with mailId : saurabh@e.com Wating for 5 seconds Wating for 4 seconds Wating for 3 seconds Wating for 2 seconds Wating for 1 seconds Exited from sendMail Exited from addEmployee Here you can see that the client waits till the mail is sent to the user. Instead we can send the response to the client after the employee is inserted into the database and process the mail sending functionality asynchronously. Lets implement this in Spring Boot. How to use @Async and @EnableAsync in Spring Boot 1. Mark the sendEmail method as @Async to execute it asynchronously.
Simply put – annotating a method of a bean with @Async will make it execute in a separate thread i.e. the caller will not wait for the completion of the called method.
@Service
public class EmailService {

    @Async
    public void sendMail(String email) {
        System.out.println("Entered in sendMail with mailId : " + email);
        try {
            int seconds = 5;
            for (int i = 1; i <= 5; i++) {
                System.out.println("Wating for " + seconds + " seconds");
                Thread.sleep(1000);
                seconds--;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Exited from sendMail");
    }
}
2. To enable asynchronous implementation add @EnableAsync to your configuration file as below.
@SpringBootApplication
@EnableAsync
public class SpringAsyncExampleApplication {

 public static void main(String[] args) {
  SpringApplication.run(SpringAsyncExampleApplication.class, args);
 }

 @Bean
 public ModelMapper getModelMapper() {
  return new ModelMapper();
 }
}
Lets run the application with these changes and fire the same request again. Output: Entered in addEmployee with : EmployeeDTO(id=null, firstName=only, lastName=fullstack, salary=1000, email=saurabh@e.com) Hibernate: call next value for employee_id_seq Hibernate: call next value for employee_id_seq Hibernate: insert into employee_data (email, first_name, last_name, salary, id) values (?, ?, ?, ?, ?) Employee saved into database Exited from addEmployee —> here the response is sent to the client Entered in sendMail with mailId : saurabh@e.com Wating for 5 seconds Wating for 4 seconds Wating for 3 seconds Wating for 2 seconds Wating for 1 seconds Exited from sendMail As you can see, server has sent the 201 HTTP response code to the client after the employee has been inserted into the database and started the sendEmail functionality in new thread wherein the client was not waiting for that method to get complete.

So what does the @Async and @EnableAsync do in the background?

@EnableAsync enables Spring’s asynchronous method execution capability. By default, Spring will be searching for an associated thread pool definition: either a unique TaskExecutor bean in the context, or an Executor bean named “taskExecutor” otherwise. If neither of the two is resolvable, a SimpleAsyncTaskExecutor will be used to process async method invocations.
@Async will create a new thread and submit in the ThreadPool.

Source Code

Download source code of Spring Rest Advance Topics from below git repository : spring-rest-advance-topics

Spring Rest Advanced Tutorial

https://www.onlyfullstack.com/spring-rest-advanced-tutorial/

Lets go to our next tutorial where we will discuss below point

6. Spring Profiles – How to use Profiles in Spring Boot? – What are Profiles in Spring? – How to implement Profiles in Spring Boot? – 1.Profiles with property files placeholders – 2.Profiles with Stereotype Annotations Blog URL – Part 6 – Spring Profiles