How to use @Async annotation in a Spring Boot Application
Asynchronous tasks are tasks that can be executed in the background without blocking the calling thread. They are commonly used in applications to improve performance and responsiveness, especially in cases where a task may take a long time to complete, such as fetching data from a remote server, processing large amounts of data, or performing complex computations. In this post we will discuss Spring Boot @Async Annotation.
Async tasks are particularly useful in applications that require responsiveness, such as web applications, where a long-running task can cause the UI to freeze and make the application unresponsive. By executing tasks asynchronously, the application can continue to respond to user input and provide feedback while the task is being executed in the background.
Spring Boot provides several annotations to support asynchronous processing in applications. One of these annotations is @Async, which allows developers to execute a method asynchronously. The @Async annotation allows methods to be executed asynchronously in a separate thread, without blocking the calling thread.
When a method is annotated with @Async, Spring Boot automatically creates a separate thread to execute the method in the background. Once the method is completed, the result is returned to the calling thread, either through a Future or a CompletableFuture.
In this write-up, we will take a deep dive into the Spring Boot @Async annotation, understand its behavior, and explore some simple and complex examples.
To use the @Async annotation, you need to do the following:
- Enable asynchronous processing in your Spring Boot application. You can do this by adding the @EnableAsync annotation to your application configuration class.
- Mark the method you want to execute asynchronously with the @Async annotation.
Here is an example of a simple Spring Boot application that uses the @Async annotation:
@SpringBootApplication
@EnableAsync
public class SimpleAsyncExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SimpleAsyncExampleApplication.class, args);
}
@Async
public void asyncMethod() {
// method body
}
}
In this example, we have marked the asyncMethod() method with the @Async annotation. When this method is called, Spring Boot creates a new thread to execute the method’s body asynchronously.
Example 1
Let’s look at a simple example that demonstrates the use of the @Async annotation. In this example, we will create a service that fetches a list of users from a database and returns the result asynchronously.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Async
public CompletableFuture<List<User>> getUsers() {
List<User> users = userRepository.findAll();
return CompletableFuture.completedFuture(users);
}
}
In this example, we have created a UserService that fetches a list of users from a UserRepository. The getUsers() method is marked with the @Async annotation, which indicates that this method should be executed asynchronously.
The getUsers() method returns a CompletableFuture, which is a Java class that represents a task that will be completed asynchronously. When the getUsers() method is called, Spring Boot creates a new thread to execute the method’s body asynchronously. Once the getUsers() method completes its execution, it returns a CompletableFuture that contains the list of users.
Here is an example of how we can use the UserService to fetch a list of users asynchronously:
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public CompletableFuture<List<User>> getUsers() {
return userService.getUsers();
}
}
In this example, we have created a UserController that exposes a REST endpoint /users that fetches a list of users using the UserService. The getUsers() method returns a CompletableFuture that contains the list of users. When this endpoint is called, Spring Boot creates a new thread to execute the getUsers() method asynchronously. Once the getUsers() method completes its execution, the list of users is returned as a CompletableFuture.
Example 2
Let’s now look at a more complex example that demonstrates the use of the @Async annotation. In this example, we will create a service that sends an email asynchronously using the JavaMail API.
@Service
public class EmailService {
@Autowired
private JavaMailSender javaMailSender;
@Async
public CompletableFuture<Boolean> sendEmail(String to, String subject, String body) {
try {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper message =</code> <code>new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.setTo(to);
message.setSubject(subject);
message.setText(body, true);
javaMailSender.send(mimeMessage);
return CompletableFuture.completedFuture(true);
} catch (MessagingException e) {
e.printStackTrace();
return CompletableFuture.completedFuture(false);
}
}
}
In this example, we have created an EmailService that sends an email using the JavaMailSender API. The sendEmail() method is marked with the @Async annotation, which indicates that this method should be executed asynchronously.
The sendEmail() method takes three parameters: the email recipient, the email subject, and the email body. The method creates a new MimeMessage and sets the recipient, subject, and body of the email. The email is then sent using the JavaMailSender API. If the email is sent successfully, the method returns a CompletableFuture containing true. If there is an error while sending the email, the method returns a CompletableFuture containing false.
Here is an example of how we can use the EmailService to send an email asynchronously:
@RestController public class EmailController
{
@Autowired
private EmailService emailService;
@PostMapping("/send-email")
public CompletableFuture<Boolean> sendEmail(@RequestBody EmailRequest emailRequest) {
String to = emailRequest.getTo();
String subject = emailRequest.getSubject();
String body = emailRequest.getBody();
return emailService.sendEmail(to, subject, body);
}
}
In this example, we have created an EmailController that exposes a REST endpoint /send-email that sends an email using the EmailService. The sendEmail() method takes an EmailRequest object as a request body. The EmailRequest object contains the email recipient, subject, and body.
When this endpoint is called, Spring Boot creates a new thread to execute the sendEmail() method asynchronously. Once the sendEmail() method completes its execution, a CompletableFuture containing true or false is returned depending on whether the email was sent successfully or not.
Conclusion
In this write-up, we have taken a deep dive into the Spring Boot @Async annotation and explored some simple and complex examples. The @Async annotation allows developers to execute a method asynchronously, which can improve application performance and responsiveness. When a method is marked with @Async, Spring Boot creates a new thread to execute that method, allowing the calling thread to continue its execution without waiting for the method to complete. The @Async annotation is a powerful feature of Spring Boot that can be used to improve the performance and responsiveness of your applications. It is important to use this feature judiciously, as executing too many methods asynchronously can lead to excessive thread creation and memory usage.
You can read about Async more on the official documentation – Annotation Interface Async
In the last post we had discussed about The Ultimate Guide to Get your website live in just 15 minutes with Google Sites. You can read that post here.
Happy Learning!
Subscribe to the BitsToGigs Newsletter