Spring MVC – Implementing Asynchronous Request Processing
Last Updated :
23 Jul, 2025
In Spring MVC, asynchronous request processing allows the server to handle requests in a non-blocking manner. This approach improves performance by freeing up resources while waiting for responses, which is especially useful for long-running tasks such as remote service calls, file processing, or database queries. Asynchronous processing can enhance server scalability and responsiveness in high-traffic applications.
Implementing Asynchronous Request Processing in Spring MVC
Asynchronous processing in Spring MVC involves handling requests using separate threads, allowing the main thread to continue processing other requests. Key components for asynchronous processing in Spring MVC include DeferredResult
, Callable
, and WebAsyncTask
.
Key Terminologies:
- @Async: A Spring annotation used to mark a method for asynchronous execution. Methods annotated with
@Async
are executed asynchronously in a separate thread, allowing the main thread to continue processing other tasks. - Callable: An interface in Java that represents a task that can be executed asynchronously. In Spring MVC, a method returning a
Callable
allows asynchronous request handling. - DeferredResult: A flexible class that allows the server to return a result later, after a delay. It is often used in event-driven applications where the completion of the task depends on external events or processes.
- WebAsyncTask: A class that extends
Callable
and provides more control over asynchronous tasks, including timeouts, custom thread pools, and task cancellation.
DeferredResult
DeferredResult
in Spring MVC is an abstraction for returning the result of a long-running request without blocking the main processing thread. It decouples the request handling from the actual response, which is provided asynchronously once an event (like a background task or external service call) completes.
When to Use DeferredResult?
Use DeferredResult
when the response depends on multiple asynchronous events, and you want to return the result only when these events are completed.
Example Usage:
@RestController
public class DeferredResultController {
@Autowired
private LongRunningService longRunningService;
@GetMapping("/async-deferred")
public DeferredResult<String> handleDeferredResult() {
DeferredResult<String> deferredResult = new DeferredResult<>();
// Simulate asynchronous task using a separate thread
new Thread(() -> {
try {
String result = longRunningService.process();
deferredResult.setResult(result);
} catch (InterruptedException e) {
deferredResult.setErrorResult("Error occurred while processing.");
}
}).start();
return deferredResult;
}
}
Key Features of DeferredResult:
- The main thread is not blocked while processing the request.
- Results can be set manually using
setResult()
, and errors can be handled using setErrorResult()
. - Supports timeouts to handle cases where the response takes too long.
WebAsyncTask
WebAsyncTask
is another way to handle asynchronous requests in Spring MVC. It extends Callable
and offers more control, including timeouts, error handling, and custom thread pools.
When to Use WebAsyncTask?
Use WebAsyncTask
when you need more control over timeouts, error handling, or want to execute tasks in different thread pools.
Example Usage:
@RestController
public class WebAsyncTaskController {
@Autowired
private LongRunningService longRunningService;
@GetMapping("/async-webasynctask")
public WebAsyncTask<String> handleWebAsyncTask() {
Callable<String> callableTask = () -> longRunningService.process();
// Create WebAsyncTask with a timeout and Callable task
WebAsyncTask<String> webAsyncTask = new WebAsyncTask<>(6000, callableTask);
// Handle timeout
webAsyncTask.onTimeout(() -> "Task timed out!");
// Handle error
webAsyncTask.onError(() -> "Error occurred while processing the task!");
return webAsyncTask;
}
}
Key Features of WebAsyncTask:
- Allows setting timeouts for long-running tasks.
- Supports error handling and fallback responses.
- Provides better control over thread pools and task management compared to
Callable
.
Callable
Callable
is a simple way to execute long-running tasks asynchronously. When a Callable
is returned from a controller method, Spring processes it in a separate thread and sends the result back when the task completes.
When to Use Callable?
Use Callable
for straightforward asynchronous tasks where the result is returned after a single task completes, and advanced error or timeout handling is not required.
Example Usage:
@RestController
public class CallableController {
@Autowired
private LongRunningService longRunningService;
@GetMapping("/async-callable")
public Callable<String> handleCallable() {
// Return a Callable that simulates a long-running task
return () -> longRunningService.process();
}
}
Key Features of Callable:
- Simplifies execution of asynchronous tasks.
- Automatically returns the result once the
Callable
completes. - No complex configuration is needed, making it ideal for simple use cases.
@Async and Thread Pool Configuration
@Async
@Async
is a Spring annotation that allows methods to be executed asynchronously in a separate thread. This enables background processing without holding up the main thread.
When to Use @Async?
Use @Async
for tasks that can be executed in the background, such as sending emails, making external API calls, or processing large datasets.
Example Usage:
@Service
public class AsyncService {
@Async
public void executeAsyncTask() throws InterruptedException {
Thread.sleep(5000); // Simulate a long-running task
System.out.println("Async task completed.");
}
}
Thread Pool Configuration for @Async
By default, @Async
methods use Spring's simple thread pool executor. For better control, you can configure a custom thread pool to define the number of concurrent threads, maximum threads, queue capacity, and more.
Java Configuration for Custom Thread Pool:
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // Minimum number of threads in the pool
executor.setMaxPoolSize(10); // Maximum number of threads
executor.setQueueCapacity(100); // Queue size before rejecting new tasks
executor.setThreadNamePrefix("AsyncTask-");
executor.initialize();
return executor;
}
}
Thread Pool Configuration via application.properties:
# Spring asynchronous configuration
spring.task.execution.pool.core-size=5
spring.task.execution.pool.max-size=10
spring.task.execution.pool.queue-capacity=100
spring.task.execution.thread-name-prefix=async-task-
Configuration Details:
core-size
: Defines the minimum number of threads the pool maintains.max-size
: The maximum number of threads allowed.queue-capacity
: Defines the size of the queue for holding tasks before rejecting them.thread-name-prefix
: Sets the prefix for thread names.
Workflow
- The client sends a request.
- The server delegates the request to the asynchronous thread pool.
- The server returns immediately, without blocking the main thread.
- Once the task is complete, the result is returned to the client.
Implementing Asynchronous Request Processing in Spring MVC
Step 1: Create a New Spring Boot Project
Create a new Spring Boot project using IntelliJ IDEA with the following options:
- Name:
spring-async-example
- Language: Java
- Type: Maven
- Packaging: Jar
Click on the Next button.
Step 2: Add Dependencies
We can add the following dependencies into the Spring Boot Project.
- Spring Web
- Lombok
- Spring Boot DevTools
Click on the Create button.
Project Structure
After project creation done successfully, the folder structure will look like the below image:
Step 3: Configure Application Properties
In the application.properties
file, configure asynchronous request timeout and thread pool settings:
spring.application.name=spring-async-example
# Asynchronous request timeout
spring.mvc.async.request-timeout=60000
# Thread pool configuration for async tasks
spring.task.execution.pool.core-size=5
spring.task.execution.pool.max-size=10
spring.task.execution.pool.queue-capacity=100
spring.task.execution.thread-name-prefix=async-task-
Step 4: Create the LongRunningService Class
Create a service class that simulates a long-running task.
LongRunningService.java:
Java
package com.gfg.springasyncexample;
import org.springframework.stereotype.Service;
@Service
public class LongRunningService {
public String process() throws InterruptedException {
// Simulate a time-consuming process (e.g., database call, API call)
Thread.sleep(5000); // Simulate delay
return "Task completed successfully!";
}
}
Step 5: Create the CallableController Class
Create the CallableController class and this class can be useful when you have the single long-running task that you want to handle the asynchronously. It automatically returns the result once the task is done.
CallableController.java:
Java
package com.gfg.springasyncexample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Callable;
@RestController
public class CallableController {
@Autowired
private LongRunningService longRunningService;
@GetMapping("/async-callable")
public Callable<String> handleCallable() {
// Return a Callable that simulates a long-running task
return () -> longRunningService.process();
}
}
Step 6: Create the DeferredResultController Class
Create the DeferredResultController class and this class is ideal for handling cases where the response might depend on the multiple asynchronous events or when you need the external events to the trigger the response.
DeferredResultController.java:
Java
package com.gfg.springasyncexample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
@RestController
public class DeferredResultController {
@Autowired
private LongRunningService longRunningService;
@GetMapping("/async-deferred")
public DeferredResult<String> handleDeferredResult() {
DeferredResult<String> deferredResult = new DeferredResult<>();
// Simulate asynchronous task using a separate thread
new Thread(() -> {
try {
String result = longRunningService.process();
deferredResult.setResult(result);
} catch (InterruptedException e) {
deferredResult.setErrorResult("Error occurred while processing.");
}
}).start();
return deferredResult;
}
}
Step 7: Create the WebAsyncTask Class
Create the WebAsyncTask class. WebAsyncTask provides the more control over the execution of the task. It allows us to define the timeouts, thread pools, and handle the errors more gracefully.
WebAsyncTaskController.java:
Java
package com.gfg.springasyncexample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.WebAsyncTask;
import java.util.concurrent.Callable;
@RestController
public class WebAsyncTaskController {
@Autowired
private LongRunningService longRunningService;
@GetMapping("/async-webasynctask")
public WebAsyncTask<String> handleWebAsyncTask() {
Callable<String> callableTask = () -> longRunningService.process();
// Create WebAsyncTask with a timeout and Callable task
WebAsyncTask<String> webAsyncTask = new WebAsyncTask<>(6000, callableTask);
// Handle timeout
webAsyncTask.onTimeout(() -> "Task timed out!");
// Handle error
webAsyncTask.onError(() -> "Error occurred while processing the task!");
return webAsyncTask;
}
}
Step 8: Main Application
This is entry point for the Spring Boot application, add the @Async anntotation to enable the asynchronous functionalities in this project.
Java
package com.gfg.springasyncexample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class SpringAsyncExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringAsyncExampleApplication.class, args);
}
}
Step 9: Run the Application
Now run the application, and it will start at port 8080.
Step 10: Testing the Application
We can test the application using postman tool.
1. Callable Output:
After calling /async-callable, we will see the message after a 5-second delay:
GET http://localhost:8080/async-callable
Response:
2. DeferredResult Output:
After calling /async-deferred, we will see the message after a 5-second delay:
GET http://localhost:8080/async-deferred
Response:
3. WebAsyncTask Output:
After calling /async-webasynctask, we will either see
Task completed successfully!
or, if the task exceeds the timeout limit:
Task timeout occurred!
Response:
The example project demonstrates the asynchronous request processing scenario, demonstrating how to delay the response to the client while handling background tasks. It can be critical in modern web applications where the server needs to handle the multiple requests without being blocked by long-running processes.
Similar Reads
Advanced Java Tutorial | Mastery in Java Programming Advanced Java typically refers to the specialized topics and advanced features of the Java programming language beyond the basics covered in Core Java. Includes concepts like Servlets, JSP (JavaServer Pages), JDBC (Java Database Connectivity), Java EE (Enterprise Edition), web services, frameworks l
13 min read
Java Enterprise Edition
Introduction to Java ServletsJava Servlet is a Java program that runs on a Java-enabled web server or application server. It handles client requests, processes them and generates responses dynamically. Servlets are the backbone of many server-side Java applications due to their efficiency and scalability.Key Features:Servlets w
7 min read
Life Cycle of a ServletThe entire life cycle of a Servlet is managed by the Servlet container, which uses the jakarta.servlet.Servlet interface to understand the Servlet object and manage it. So, before creating a Servlet object, let's first understand the life cycle of the Servlet object, which is actually understanding
6 min read
Introduction to JSPJavaServer Pages (JSP) is a server-side technology that creates dynamic web applications. It allows developers to embed Java code directly into HTML pages and it makes web development more efficient.JSP is an advanced version of Servlets. It provides enhanced capabilities for building scalable and p
4 min read
JSP ArchitectureJSP (Java Server Pages) uses a three-tier architecture with a client, web server, and database. When the client sends a request, the web server's JSP engine processes the JSP file by converting it into a servlet, compiling, and executing it. The generated HTML is sent back to the client. The followi
2 min read
JSF | Java Server FacesJSF technology includes a set of APIs, which represent different UI components and helps in managing their states. These APIs further help in handling events on the UI components and validate user inputs through the UI components. JSF framework provides the flexibility of creating simple as well as
4 min read
Enterprise Java Beans (EJB)Note java.beans: This package has been deprecated in Java 9 and later versions, in favor of using annotations and other modern ways of creating beans. Enterprise Java Beans (EJB) is one of the several Java APIs for standard manufacture of enterprise software. EJB is a server-side software element th
4 min read
Multithreading
Concurrency
java.util.concurrent PackageJava Concurrency package covers concurrency, multithreading, and parallelism on the Java platform. Concurrency is the ability to run several or multi programs or applications in parallel. The backbone of Java concurrency is threads (a lightweight process, which has its own files and stacks and can a
9 min read
Java.util.concurrent.Executor interface with ExamplesThe concurrent API in Java provides a feature known as an executor that initiates and controls the execution of threads. As such, an executor offers an alternative to managing threads using the thread class. At the core of an executor is the Executor interface. It refers to the objects that execute
1 min read
Java.util.concurrent.ExecutorService Interface with ExamplesThe ExecutorService interface extends Executor by adding methods that help manage and control the execution of threads. It is defined in java.util.concurrent package. It defines methods that execute the threads that return results, a set of threads that determine the shutdown status. The ExecutorSer
3 min read
Java Runnable Interfacejava.lang.Runnable is an interface that is to be implemented by a class whose instances are intended to be executed by a thread. There are two ways to start a new Thread - Subclass Thread and implement Runnable. There is no need to subclass a Thread when a task can be done by overriding only the run
3 min read
Callable and Future in JavaIn Java, multithreading allows tasks to run concurrently, improving performance and responsiveness. Traditionally, developers used the Runnable interface to define tasks, but it has two major limitations: it cannot return a result and cannot throw checked exceptions.To overcome these, Java introduce
2 min read
Difference Between Callable and Runnable in Javajava.lang.Runnable is an interface that is to be implemented by a class whose instances are intended to be executed by a thread. There are two ways to start a new Thread â Subclass Thread and implement Runnable. There is no need of sub-classing Thread when a task can be done by overriding only run()
3 min read
JDBC (Java Database Connectivity)
JDBC (Java Database Connectivity)JDBC is an API that helps applications to communicate with databases, it allows Java programs to connect to a database, run queries, retrieve, and manipulate data. Because of JDBC, Java applications can easily work with different relational databases like MySQL, Oracle, PostgreSQL, and more.JDBC Arc
5 min read
JDBC DriversDBC drivers are software components that enable Java applications to communicate with different types of databases. Each database (like MySQL, Oracle, or PostgreSQL) requires a specific JDBC driver that translates Java JDBC calls into the database-specific protocol.The JDBC classes are contained in
4 min read
Establishing JDBC Connection in JavaBefore performing any database operations, you first need to establish a connection using JDBC. This connection acts like a communication channel through which SQL queries are sent and results are received. Setting up this connection involves loading the database driver, specifying the database URL,
6 min read
Types of Statements in JDBCIn Java, the Statement interface in JDBC (Java Database Connectivity) is used to create and execute SQL queries in Java applications. JDBC provides three types of statements to interact with the database:StatementPrepared StatementCallable Statement1. StatementA Statement object is used for general-
5 min read
Java Frameworks
Introduction to Spring FrameworkThe Spring Framework is a lightweight Java framework widely used for building scalable, maintainable enterprise applications. It offers a comprehensive programming and configuration model for Java-based development.Benefits of Using Spring FrameworkSimplified Development: Spring reduces boilerplate
7 min read
Spring - Understanding Inversion of Control with ExampleSpring IoC (Inversion of Control) Container is the core of the Spring Framework. It creates and manages objects (beans), injects dependencies and manages their life cycles. It uses Dependency Injection (DI), based on configurations from XML files, Java-based configuration, annotations or POJOs. Sinc
6 min read
Introduction to Spring BootSpring is one of the most popular frameworks for building enterprise applications, but traditional Spring projects require heavy XML configuration, making them complex for beginners.Spring Boot solves this problem by providing a ready-to-use, production-grade framework on top of Spring. It eliminate
4 min read
Spring - MVC FrameworkThe Spring MVC Framework follows the Model-View-Controller architectural design pattern, which works around the Front Controller, i.e., the Dispatcher Servlet. The Dispatcher Servlet handles and dispatches all incoming HTTP requests to the appropriate controller. It uses @Controller and @RequestMapp
4 min read
How to Create a REST API using Java Spring Boot?Representational State Transfer (REST) is a software architectural style that defines a set of constraints for creating web services. RESTful web services allow systems to access and manipulate web resources through a uniform and predefined set of stateless operations. Unlike SOAP, which exposes its
4 min read
What is Spring Data JPA?Spring Data JPA is a powerful framework that simplifies database access in Spring Boot applications by providing an abstraction layer over the Java Persistence API (JPA). It enables seamless integration with relational databases using Object-Relational Mapping (ORM), eliminating the need for boilerp
6 min read
Spring - JDBC TemplateIn this article, we will discuss the Spring JDBC Template and how to configure the JDBC Template to execute queries. Spring JDBC Template provides a fluent API that improves code simplicity and readability, and the JDBC Template is used to connect to the database and execute SQL Queries. What is JDB
7 min read
Spring Hibernate Configuration and Create a Table in DatabaseSpring Boot and Hibernate are a powerful combination for building scalable and efficient database-driven applications. Spring Boot simplifies application development by reducing boilerplate code, while Hibernate, a popular ORM (Object-Relational Mapping) framework, enables easy database interactions
4 min read
Aspect Oriented Programming (AOP) in Spring FrameworkSpring AOP (Aspect-Oriented Programming) is a programming technique in the Spring Framework that helps separate cross-cutting concerns (like logging, security, transactions) from the main business logic. Instead of adding this logic inside every class, AOP allows you to write it once and apply it wh
3 min read
Introduction to Spring Security and its FeaturesSpring Security is a powerful authentication and authorization framework used to secure Java-based web applications. It easily integrates with Spring Boot and provides advanced security mechanisms such as OAuth2, JWT-based authentication, role-based access control, and protection against common vuln
3 min read
What is Spring Cloud?There are many reasons to use Spring Framework for example if you want faster development, less configuration, auto-configuration, embedded server, production-ready application, and many more. But apart from that most importantly we have ready-made support for microservices and this ready-made suppo
2 min read
Introduction and Working of Struts Web FrameworkStruts is an open-source web application framework developed by Apache Software Foundation, it is used to create a web application based on servlet and JSP. It depends on the MVC (Model View Controller) framework. Struts are thoroughly useful in building J2EE (Java 2 Platform, Enterprise Edition) ap
3 min read
JUnit
Introduction to JUnit 5JUnit is a Testing Framework. The Junit 5 is the latest version of the testing framework, and it has a lot of features when compared with Junit 4. JUnit 5, also known as JUnit Jupiter. It introduces several new features and improvements over its predecessor, JUnit 4, making it more powerful and flex
8 min read
JUnit 5 vs JUnit 4JUnit 4 and JUnit 5 both are Java-based testing frameworks, The JUnit 5 is the advanced testing framework when compared with JUnit 4. The JUnit provides a lot of features like Annotation-based coding, parallel test execution, and other features. Difference between JUnit 5 and JUnit 4TopicJUnit 5JUni
4 min read
How to Write Test Cases in Java Application using Mockito and Junit?Mockito is an open-source testing framework used for unit testing of Java applications. It plays a vital role in developing testable applications. Mockito is used to mock interfaces so that a dummy functionality can be added to a mock interface that can be used in Unit Testing. Unit Testing is a typ
4 min read
Unit Testing in Spring Boot Project using Mockito and JunitSpring Boot is a Java-based framework built on top of Spring that simplifies application development with minimal configuration. Itâs ideal for creating production-ready applications quickly, thanks to features like embedded servers, auto-configuration and reduced boilerplate code.Mockito is an open
4 min read
JUnit 5 - Test Suites with ExampleJUnit 5 encourages a modular approach to test creation with its test suites. These suites function as containers, bundling multiple test classes for easier management and collective execution within a single run. In this article, we will learn about JUnit 5 - Test Suites. Test SuiteIn JUnit 5, a tes
2 min read
JUnit 5 â JaCoCo Code CoverageIn simple terms, code coverage means measuring the percentage of lines of code that are executed during automated tests. For example, if you have a method containing 100 lines of code and you are writing a test case for it, code coverage tells you briefly how many of those lines were actively exerci
5 min read