📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
✅ Some premium posts are free to read — no account needed. Follow me on Medium to stay updated and support my writing.
🎓 Top 10 Udemy Courses (Huge Discount): Explore My Udemy Courses — Learn through real-time, project-based development.
▶️ Subscribe to My YouTube Channel (172K+ subscribers): Java Guides on YouTube
Step 1: Enable Async Support
Step 2: Add @Async Annotation to a Method
Step 3: Executor (Customize of default)
@Bean("threadPoolTaskExecutor") public TaskExecutor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(20); executor.setMaxPoolSize(1000); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setThreadNamePrefix("Async-"); return executor; }
What we’ll build?
Tools and Technologies Used
- Spring Boot - 3
- JDK - 17 or later
- Spring Framework - 6
- Maven - 3.2+
- IDE - Eclipse or Spring Tool Suite (STS)
Create and Set up the Spring Boot Project
- Generate: Maven Project
- Java Version: 17 (Default)
- Spring Boot: 3.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
Project Directory Structure
The pom.xml File
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.guides.springboot</groupId>
<artifactId>springboot-async-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-async-example</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.4</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Create a representation of a GitHub User
package net.guides.springboot.springbootasyncexample.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
private String name;
private String blog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBlog() {
return blog;
}
public void setBlog(String blog) {
this.blog = blog;
}
@Override
public String toString() {
return "User [name=" + name + ", blog=" + blog + "]";
}
}
Create a GitHub lookup service
package net.guides.springboot.springbootasyncexample.service;
import java.util.concurrent.CompletableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import net.guides.springboot.springbootasyncexample.model.User;
@Service
public class GitHubLookupService {
private static final Logger logger = LoggerFactory.getLogger(GitHubLookupService.class);
private final RestTemplate restTemplate;
public GitHubLookupService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
@Async("threadPoolTaskExecutor")
public CompletableFuture < User > findUser(String user) throws InterruptedException {
logger.info("Looking up " + user);
String url = String.format("https://api.github.com/users/%s", user);
User results = restTemplate.getForObject(url, User.class);
// Artificial delay of 1s for demonstration purposes
Thread.sleep(1000 L);
return CompletableFuture.completedFuture(results);
}
}
Make the application executable
package net.guides.springboot.springbootasyncexample;
import java.util.concurrent.CompletableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import net.guides.springboot.springbootasyncexample.model.User;
import net.guides.springboot.springbootasyncexample.service.GitHubLookupService;
@SpringBootApplication
@EnableAsync
public class SpringbootAsyncApplication implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(SpringbootAsyncApplication.class);
@Autowired
private GitHubLookupService gitHubLookupService;
@Bean("threadPoolTaskExecutor")
public TaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(1000);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("Async-");
return executor;
}
public static void main(String[] args) {
SpringApplication.run(SpringbootAsyncApplication.class, args);
}
@Override
public void run(String...args) throws Exception {
// Start the clock
long start = System.currentTimeMillis();
// Kick of multiple, asynchronous lookups
CompletableFuture < User > page1 = gitHubLookupService.findUser("PivotalSoftware");
CompletableFuture < User > page2 = gitHubLookupService.findUser("CloudFoundry");
CompletableFuture < User > page3 = gitHubLookupService.findUser("Spring-Projects");
CompletableFuture < User > page4 = gitHubLookupService.findUser("RameshMF");
// Wait until they are all done
CompletableFuture.allOf(page1, page2, page3, page4).join();
// Print results, including elapsed time
logger.info("Elapsed time: " + (System.currentTimeMillis() - start));
logger.info("--> " + page1.get());
logger.info("--> " + page2.get());
logger.info("--> " + page3.get());
logger.info("--> " + page4.get());
}
}
page.get() is blocking operation
ReplyDelete