DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

  1. DZone
  2. Coding
  3. Frameworks
  4. Spring Boot: Creating Asynchronous Methods Using @Async Annotation

Spring Boot: Creating Asynchronous Methods Using @Async Annotation

Need help creating asynchronous methods using the @Async annotation? Check out this tutorial to learn how in Spring Boot.

By 
Ramesh Fadatare user avatar
Ramesh Fadatare
·
Updated Nov. 15, 18 · Tutorial
Likes (12)
Comment (3)

Save
Tweet
Share
315.7K Views

Join the DZone community and get the full member experience.

Join For Free

In this article, we’ll explore the asynchronous execution support in Spring or Spring Boot using Spring's @Async annotation.

We will annotate a bean method;  @Async will make it execute in a separate thread, i.e. the caller will not wait for the completion of the called method.

If you have been already working on a Spring or Spring Boot application, and you have a requirement to use as an asynchronous mechanism, then these three quick steps will help you get started.

Step 1: Enable Async Support

Let’s start by enabling asynchronous processing with Java configuration by simply adding the  @EnableAsync to a configuration class: The @EnableAsync annotation switches Spring’s ability to run @Async methods in a background thread pool.

Step 2: Add @Async Annotation to a Method

Make sure that the method we are annotating with @Async needs to be public so that it can be proxied. And, self-invocation doesn’t work because it bypasses the proxy and calls the underlying method directly.

Step 3: Executor (Customize of Default)

Let's customize the ThreadPoolTaskExecutor. In our case, we want to limit the number of concurrent threads to two and limit the size of the queue to 500. There are many more things you can tune. By default, a SimpleAsyncTaskExecutor is used.

9
1
@Bean("threadPoolTaskExecutor")
2
    public TaskExecutor getAsyncExecutor() {
3
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
4
        executor.setCorePoolSize(20);
5
        executor.setMaxPoolSize(1000);
6
        executor.setWaitForTasksToCompleteOnShutdown(true);
7
        executor.setThreadNamePrefix("Async-");
8
        return executor;
9
    }


That's all, these are three quick steps that help you create asynchronous services using Spring or Spring Boot. Let's develop a complete example to demonstrate how we can create asynchronous services using Spring or Spring Boot.

Learn and master in Spring Boot at  Spring Boot Tutorial

What We’ll Build

We’ll build a lookup service that queries GitHub user information and retrieves data through GitHub’s API. One approach to scaling services is to run expensive jobs in the background and wait for the results using Java’s CompletableFuture interface. Java’s CompletableFuture is an evolution of the regular  Future. It makes it easy to pipeline multiple asynchronous operations, merging them into a single asynchronous computation.

Tools and Technologies Used

  • Spring Boot - 2.0.6.RELEASE
  • JDK - 1.8 or later
  • Spring Framework - 5.0.9 RELEASE
  • Maven - 3.2+
  • IDE - Eclipse or Spring Tool Suite (STS)

Create and Import Spring Boot Project

There are many ways to create a Spring Boot application. The simplest way is to use Spring Initializr at http://start.spring.io/, which is an online Spring Boot application generator. Look at the above diagram, we have specified the following details:

  • Generate: Maven Project
  • Java Version: 1.8 (Default)
  • Spring Boot:2.0.4
  • Group: net.javaguides.springboot
  • Artifact: springboot-async-example
  • Name: springboot-async-example
  • Description: Demo project for Spring Boot
  • Package Name : net.guides.springboot.springbootasyncexample
  • Packaging: jar (This is the default value)
  • Dependencies: Web

Once all the details are entered, click on the Generate Project button. It will generate a Spring Boot project and download it. Next, unzip the downloaded zip file and import it into your favorite IDE.

Project Directory Structure

Below, the diagram shows a project structure for reference:

The pom.xml File

1
<?xml version="1.0" encoding="UTF-8"?>
2
<project
3
    xmlns="http://maven.apache.org/POM/4.0.0"
4
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
6
    <modelVersion>4.0.0</modelVersion>
7
    <groupId>net.guides.springboot</groupId>
8
    <artifactId>springboot-async-example</artifactId>
9
    <version>0.0.1-SNAPSHOT</version>
10
    <packaging>jar</packaging>
11
    <name>springboot-async-example</name>
12
    <description>Demo project for Spring Boot</description>
13
    <parent>
14
        <groupId>org.springframework.boot</groupId>
15
        <artifactId>spring-boot-starter-parent</artifactId>
16
        <version>2.0.6.RELEASE</version>
17
        <relativePath/>
18
        <!-- lookup parent from repository -->
19
    </parent>
20
    <properties>
21
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
22
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
23
        <java.version>1.8</java.version>
24
    </properties>
25
    <dependencies>
26
        <dependency>
27
            <groupId>org.springframework.boot</groupId>
28
            <artifactId>spring-boot-starter-web</artifactId>
29
        </dependency>
30
        <dependency>
31
            <groupId>org.springframework.boot</groupId>
32
            <artifactId>spring-boot-starter-test</artifactId>
33
            <scope>test</scope>
34
        </dependency>
35
    </dependencies>
36
    <build>
37
        <plugins>
38
            <plugin>
39
                <groupId>org.springframework.boot</groupId>
40
                <artifactId>spring-boot-maven-plugin</artifactId>
41
            </plugin>
42
        </plugins>
43
    </build>
44
</project>


Create a Representation of a GitHub User

Let's create a GitHub User model class with name and blog fields.

​x
1
package net.guides.springboot.springbootasyncexample.model;
2
​
3
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4
​
5
@JsonIgnoreProperties(ignoreUnknown = true)
6
public class User {
7
​
8
    private String name;
9
    private String blog;
10
​
11
    public String getName() {
12
        return name;
13
    }
14
​
15
    public void setName(String name) {
16
        this.name = name;
17
    }
18
​
19
    public String getBlog() {
20
        return blog;
21
    }
22
​
23
    public void setBlog(String blog) {
24
        this.blog = blog;
25
    }
26
​
27
    @Override
28
    public String toString() {
29
        return "User [name=" + name + ", blog=" + blog + "]";
30
    }
31
}


Note that Spring uses the Jackson JSON library to convert GitHub’s JSON response into a User object. The @JsonIgnoreProperties annotation signals Spring to ignore any attributes not listed in the class. This makes it easy to make REST calls and produce domain objects. In this article, we are only grabbing the name and the blog URL for demonstration purposes.

Create a GitHub Lookup Service

Next, we need to create a service that queries GitHub to find user information.

34
1
package net.guides.springboot.springbootasyncexample.service;
2
​
3
import java.util.concurrent.CompletableFuture;
4
​
5
import org.slf4j.Logger;
6
import org.slf4j.LoggerFactory;
7
import org.springframework.boot.web.client.RestTemplateBuilder;
8
import org.springframework.scheduling.annotation.Async;
9
import org.springframework.stereotype.Service;
10
import org.springframework.web.client.RestTemplate;
11
​
12
import net.guides.springboot.springbootasyncexample.model.User;
13
​
14
@Service
15
public class GitHubLookupService {
16
​
17
    private static final Logger logger = LoggerFactory.getLogger(GitHubLookupService.class);
18
​
19
    private final RestTemplate restTemplate;
20
​
21
    public GitHubLookupService(RestTemplateBuilder restTemplateBuilder) {
22
        this.restTemplate = restTemplateBuilder.build();
23
    }
24
​
25
    @Async("threadPoolTaskExecutor")
26
    public CompletableFuture < User > findUser(String user) throws InterruptedException {
27
        logger.info("Looking up " + user);
28
        String url = String.format("https://api.github.com/users/%s", user);
29
        User results = restTemplate.getForObject(url, User.class);
30
        // Artificial delay of 1s for demonstration purposes
31
        Thread.sleep(1000 L);
32
        return CompletableFuture.completedFuture(results);
33
    }
34
}


The GitHubLookupService class uses Spring’s RestTemplate to invoke a remote REST point (api.github.com/users/) and then convert the answer into a User object. Spring Boot automatically provides a RestTemplateBuilder that customizes the defaults with any auto-configuration bits (i.e. MessageConverter). The findUsermethod is flagged with Spring’s @Async annotation, indicating it will run on a separate thread. The method’s return type is CompletableFuture, instead of User, a requirement for any asynchronous service. This code uses the completedFuture method to return a CompletableFuture instance, which is already complete with a result of the GitHub query.

Make the Application Executable

To run a sample, you can create an executable jar. Let's use CommandLineRunner that injects the GitHubLookupService and calls that service four times to demonstrate the method is executed asynchronously.

62
1
package net.guides.springboot.springbootasyncexample;
2
​
3
import java.util.concurrent.CompletableFuture;
4
​
5
import org.slf4j.Logger;
6
import org.slf4j.LoggerFactory;
7
import org.springframework.beans.factory.annotation.Autowired;
8
import org.springframework.boot.CommandLineRunner;
9
import org.springframework.boot.SpringApplication;
10
import org.springframework.boot.autoconfigure.SpringBootApplication;
11
import org.springframework.context.annotation.Bean;
12
import org.springframework.core.task.TaskExecutor;
13
import org.springframework.scheduling.annotation.EnableAsync;
14
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
15
​
16
import net.guides.springboot.springbootasyncexample.model.User;
17
import net.guides.springboot.springbootasyncexample.service.GitHubLookupService;
18
​
19
@SpringBootApplication
20
@EnableAsync
21
public class SpringbootAsyncApplication implements CommandLineRunner {
22
​
23
    private static final Logger logger = LoggerFactory.getLogger(SpringbootAsyncApplication.class);
24
​
25
    @Autowired
26
    private GitHubLookupService gitHubLookupService;
27
​
28
    @Bean("threadPoolTaskExecutor")
29
    public TaskExecutor getAsyncExecutor() {
30
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
31
        executor.setCorePoolSize(20);
32
        executor.setMaxPoolSize(1000);
33
        executor.setWaitForTasksToCompleteOnShutdown(true);
34
        executor.setThreadNamePrefix("Async-");
35
        return executor;
36
    }
37
​
38
    public static void main(String[] args) {
39
        SpringApplication.run(SpringbootAsyncApplication.class, args);
40
    }
41
​
42
    @Override
43
    public void run(String...args) throws Exception {
44
        // Start the clock
45
        long start = System.currentTimeMillis();
46
​
47
        // Kick of multiple, asynchronous lookups
48
        CompletableFuture < User > page1 = gitHubLookupService.findUser("PivotalSoftware");
49
        CompletableFuture < User > page2 = gitHubLookupService.findUser("CloudFoundry");
50
        CompletableFuture < User > page3 = gitHubLookupService.findUser("Spring-Projects");
51
        CompletableFuture < User > page4 = gitHubLookupService.findUser("RameshMF");
52
        // Wait until they are all done
53
        CompletableFuture.allOf(page1, page2, page3, page4).join();
54
​
55
        // Print results, including elapsed time
56
        logger.info("Elapsed time: " + (System.currentTimeMillis() - start));
57
        logger.info("--> " + page1.get());
58
        logger.info("--> " + page2.get());
59
        logger.info("--> " + page3.get());
60
        logger.info("--> " + page4.get());
61
    }
62
}


The  @EnableAsync annotation switches on Spring’s ability to run @Async methods in a background thread pool. This class also customizes the used Executor. In our case, we want to limit the number of concurrent threads to two and limit the size of the queue to 500. There are many more things you can tune. By default, a SimpleAsyncTaskExecutor is used.

Running Application

There are two ways we can start the standalone Spring Boot application.

  • We are using Maven to run the application using ./mvnw spring-boot:run. Or, you can build the JAR file with ./mvnw clean package. Then, you can run the JAR file:
1
1
java -jar target/springboot-async-example.jar


  • Below diagram shows how to run your Spring Boot application from an IDE — right click, run the  SpringbootAsyncApplication.main() method as a standalone Java class.

Output

When we run the application, we will see the following output:

Learn and master in Spring Boot at  Spring Boot Tutorial

The source code of this article available on my GitHub repository.

References

  • https://spring.io/guides/gs/async-method/
  • https://www.baeldung.com/spring-async
  • Spring Boot Tutorial
Spring Framework Spring Boot Annotation

Published at DZone with permission of Ramesh Fadatare. See the original article here.

Opinions expressed by DZone contributors are their own.

Partner Resources

×

    November 16, 2018 Daily Digest

  • Spring Boot: Creating Asynchronous Methods Using...

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!