Mastering Asynchronous APIs in Spring Boot 2.7: Boost Concurrency and Performance
This guide explains why asynchronous request interfaces are essential for high‑concurrency Spring Boot applications, outlines their advantages and typical use cases, and provides step‑by‑step code examples for DeferredResult, Callable, ResponseBodyEmitter, StreamingResponseBody, and reactive Mono implementations.
Overview
In modern internet applications, growing user numbers and increasing business complexity make concurrency a major challenge. Synchronous request interfaces often block threads, waste resources, and degrade response performance. Asynchronous request interfaces solve these problems by freeing threads, improving throughput, and enhancing system maintainability.
Advantages of Asynchronous Interfaces
Non‑blocking: Requests do not hold the calling thread, allowing other tasks to proceed.
Resource efficiency: Threads are released early, increasing overall resource utilization.
Decoupling: Reduces coupling between services, facilitating distributed system calls.
Better error handling: Exceptions are captured in separate threads without affecting the main flow.
Flexible control flow: Callbacks or Promise‑like mechanisms enable more adaptable processing.
Typical Application Scenarios
High‑concurrency traffic where thread blocking must be avoided.
Time‑consuming operations such as network I/O or disk access.
Real‑time data processing like streaming or stock trading.
Business workflows composed of independent asynchronous tasks.
Calling external APIs that have long response times.
Practical Asynchronous Implementations in Spring Boot
4.1 DeferredResult
When servlet async support is enabled, a controller can return a DeferredResult that is completed later, freeing the Tomcat thread almost immediately.
<code>@GetMapping("/deferred")
@ResponseBody
public DeferredResult<Map<String, Object>> deferred(){
long start = System.currentTimeMillis();
System.out.printf("%s - 开始时间:%d%n", Thread.currentThread().getName(), start);
DeferredResult<Map<String, Object>> deferredResult = new DeferredResult<>();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
Map<String, Object> result = new HashMap<>();
result.put("code", 1);
result.put("data", "你的业务数据");
deferredResult.setResult(result);
} catch (InterruptedException e) {}
}).start();
long end = System.currentTimeMillis();
System.out.printf("%s - 结束时间:%d%n", Thread.currentThread().getName(), end);
System.out.printf("总耗时:%d毫秒%n", (end - start));
return deferredResult;
}
</code>4.2 Callable
Using java.util.concurrent.Callable lets Spring execute the logic in a task‑executor thread pool.
<code>@GetMapping("/callable")
public Callable<Map<String, Object>> callable() {
long start = System.currentTimeMillis();
System.out.printf("%s - 开始时间:%d%n", Thread.currentThread().getName(), start);
Callable<Map<String, Object>> callable = new Callable<Map<String, Object>>() {
public Map<String, Object> call() throws Exception {
Map<String, Object> result = new HashMap<>();
try {
TimeUnit.SECONDS.sleep(3);
result.put("code", 1);
result.put("data", "你的业务数据");
} catch (InterruptedException e) {}
return result;
}
};
long end = System.currentTimeMillis();
System.out.printf("%s - 结束时间:%d%n", Thread.currentThread().getName(), end);
System.out.printf("总耗时:%d毫秒%n", (end - start));
return callable;
}
</code>4.3 ResponseBodyEmitter
For streaming multiple values, ResponseBodyEmitter writes each object to the HTTP response as it becomes available.
<code>private ResponseBodyEmitter emitter;
@GetMapping("/emitter")
public ResponseBodyEmitter emitter() throws Exception {
ResponseBodyEmitter bodyEmitter = new ResponseBodyEmitter(-1L);
this.emitter = bodyEmitter;
return bodyEmitter;
}
@GetMapping("/sender")
public void sender() throws Exception {
this.emitter.send(System.currentTimeMillis());
}
@GetMapping("/complete")
public void complete() throws Exception {
this.emitter.complete();
}
</code>4.4 StreamingResponseBody
When you need to write directly to the response output stream (e.g., file download), StreamingResponseBody provides a low‑level way to stream data.
<code>@GetMapping("/stream")
public ResponseEntity<StreamingResponseBody> stream() {
long start = System.currentTimeMillis();
System.out.printf("%s - 开始时间:%d%n", Thread.currentThread().getName(), start);
StreamingResponseBody stream = new StreamingResponseBody() {
@Override
public void writeTo(OutputStream outputStream) throws IOException {
outputStream.write(String.valueOf("当前时间: " + System.currentTimeMillis() + "<br/>").getBytes());
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {}
outputStream.write(String.valueOf("当前时间: " + System.currentTimeMillis() + "<br/>").getBytes());
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {}
outputStream.write(String.valueOf("当前时间: " + System.currentTimeMillis() + "<br/>").getBytes());
}
};
MultiValueMap<String, String> headers = new HttpHeaders();
headers.add("Content-Type", "text/html;charset=UTF-8");
ResponseEntity<StreamingResponseBody> response = new ResponseEntity<>(stream, headers, HttpStatus.OK);
long end = System.currentTimeMillis();
System.out.printf("%s - 结束时间:%d%n", Thread.currentThread().getName(), end);
System.out.printf("总耗时:%d毫秒%n", (end - start));
return response;
}
</code>4.5 Reactive Mono
Spring MVC can return reactive types such as Mono for non‑blocking processing.
<code>@GetMapping("/mono")
public Mono<Map<String, Object>> mono() {
long start = System.currentTimeMillis();
System.out.printf("%s - 开始时间:%d%n", Thread.currentThread().getName(), start);
Mono<Map<String, Object>> mono = Mono.defer(() -> {
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {}
Map<String, Object> result = new HashMap<>();
result.put("code", 1);
result.put("data", "你的业务数据");
return Mono.just(result);
});
long end = System.currentTimeMillis();
System.out.printf("%s - 结束时间:%d%n", Thread.currentThread().getName(), end);
System.out.printf("总耗时:%d毫秒%n", (end - start));
return mono;
}
</code>Conclusion
Asynchronous request interfaces in Spring provide effective solutions for high‑concurrency, time‑consuming operations, and real‑time data processing. By freeing threads and leveraging non‑blocking patterns, they significantly improve response performance and resource utilization.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.