5 Core Techniques to Build Resilient, High‑Availability APIs with Spring Boot
This article walks through building a fault‑tolerant Spring Boot 3.5.0 API using Resilience4j, covering circuit breaking, rate limiting, timeout handling, bulkhead isolation, and retry strategies, complete with configuration snippets, code examples, and execution‑order adjustments.
Introduction
In distributed systems and micro‑service architectures, inter‑service dependencies introduce latency, timeouts, and failures that can cascade into system‑wide outages. Protecting critical API endpoints with resilience patterns—circuit breaking, rate limiting, isolation, timeout, and retry—helps prevent resource exhaustion and ensures rapid failure recovery.
Environment
Spring Boot version 3.5.0 is used for all examples.
Practical Case
2.1 Dependency Setup
Add the following Maven dependencies (choose the appropriate Resilience4j starter for Spring Boot 2 or 3):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
<version>2.3.0</version>
</dependency>For Spring Boot 2, use resilience4j-spring-boot2 instead.
2.2 Circuit Breaker
The circuit breaker is implemented as a finite‑state machine with states CLOSED , OPEN , HALF‑OPEN , plus DISABLED and FORCED‑OPEN . It can use a count‑based or time‑based sliding window to record recent call outcomes.
Example code:
@GetMapping("/query")
@CircuitBreaker(name = "api.cb", fallbackMethod = "cbFallback")
public ResponseEntity<?> circuitbreaker(String name) {
// Simulate error
System.err.println(1 / 0);
return ResponseEntity.ok("api ok...");
}
public ResponseEntity<?> cbFallback(String name, Exception e) {
return ResponseEntity.ok(Map.of(
"code", -1,
"message", "熔断, " + e.getMessage(),
"param", name));
}Configuration (YAML):
resilience4j:
ratelimiter:
instances:
'[api.rate]':
# Maximum requests per refresh period
limit-for-period: 20
# Refresh period
limit-refresh-period: 10s
# Default wait time for a thread to acquire permission
timeout-duration: 1sRunning result (image omitted for brevity).
2.3 Rate Limiter
Rate limiting protects API scalability by rejecting excess traffic, improving stability.
Example code:
@GetMapping("/query")
@CircuitBreaker(name = "api.cb", fallbackMethod = "cbFallback")
@RateLimiter(name = "api.rate", fallbackMethod = "rateFallback")
public ResponseEntity<?> circuitbreaker(String name) {
// ...
}
public ResponseEntity<?> rateFallback(String name, Exception e) {
return ResponseEntity.ok(Map.of(
"code", -1,
"message", "限流, " + e.getMessage(),
"param", name));
}Configuration (YAML):
resilience4j:
ratelimiter:
instances:
'[api.rate]':
limit-for-period: 2
limit-refresh-period: 10s
timeout-duration: 1sRunning result (image omitted).
2.4 Timeout
Timeout protection prevents long‑running downstream calls from blocking threads and exhausting resources. Setting an appropriate timeout enables fast failure.
Example code (asynchronous return type required):
// Return type must be asynchronous, e.g., CompletableFuture
@GetMapping("/query")
@TimeLimiter(name = "api.timeout", fallbackMethod = "timeoutFallback")
public CompletableFuture<?> circuitbreaker(String name) throws Exception {
return CompletableFuture.supplyAsync(() -> {
// Simulate delay
try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException ignored) {}
return "api ok";
});
}
public CompletableFuture<?> timeoutFallback(String name, Exception e) {
return CompletableFuture.supplyAsync(() ->
Map.of("code", -1, "message", "超时, " + e.getMessage(), "param", name));
}Configuration (YAML):
resilience4j:
timelimiter:
instances:
'[api.timeout]':
timeout-duration: 1sRunning result (image omitted).
2.5 Isolation (Bulkhead)
Resilience4j offers two bulkhead implementations:
SemaphoreBulkhead – uses a semaphore and works with any thread or I/O model.
FixedThreadPoolBulkhead – uses a bounded queue and a fixed‑size thread pool.
Example code (semaphore bulkhead):
@GetMapping("/query")
@Bulkhead(name = "api.bulk", fallbackMethod = "bulkFallback", type = Type.SEMAPHORE)
public CompletableFuture<?> query(String name) throws Exception {
System.err.printf("%s - 执行任务%n", Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(5);
return CompletableFuture.completedFuture("api ok");
}
public CompletableFuture<?> bulkFallback(String name, Exception e) {
return CompletableFuture.supplyAsync(() ->
Map.of("code", -1, "message", "隔离, " + e.getMessage(), "param", name));
}Configuration (YAML):
resilience4j:
bulkhead:
instances:
'[api.bulk]':
max-concurrent-calls: 1
max-wait-duration: 1sRunning result (images omitted).
2.6 Retry
Retry automatically re‑issues failed requests after transient faults such as network glitches or timeouts. Properly tuning attempts and intervals avoids cascading failures.
Example code:
@GetMapping("/query")
@Retry(name = "api.retry", fallbackMethod = "retryFallback")
public ResponseEntity<?> query(String name) throws Exception {
System.err.printf("%s - 执行任务%n", Thread.currentThread().getName());
System.err.println(1 / 0);
return ResponseEntity.ok("api ok");
}
public ResponseEntity<?> retryFallback(String name, Exception e) {
return ResponseEntity.ok(Map.of(
"code", -1,
"message", "重试, " + e.getMessage(),
"param", name));
}Configuration (YAML):
resilience4j:
retry:
instances:
'[api.retry]':
max-attempts: 3
wait-duration: 2s
retry-exceptions:
- java.lang.ArithmeticExceptionRunning result (images omitted).
2.7 Summary of the Five Features
All five resilience features are implemented as Spring AOP aspects. Their default execution order is shown in the diagram (image omitted). To adjust the order, modify the aspect order properties:
resilience4j:
circuitbreaker:
circuitBreakerAspectOrder: 1
retry:
retryAspectOrder: 2Adjusting these values changes which aspect runs first when a request hits the endpoint.
Conclusion
By integrating Resilience4j with Spring Boot 3, developers can protect API endpoints against failures, overload, and latency, achieving a more robust and highly available micro‑service architecture.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
