Backend Development 8 min read

Mastering Resilience4j: Real-World Spring Boot 3 Circuit Breaker Cases

This article explains why circuit breakers are essential for third‑party API calls, introduces the lightweight Resilience4j library, and provides step‑by‑step Spring Boot 3 examples—including Maven setup, RestTemplate and WebClient integrations, annotation usage, and both default and custom configurations—complete with code snippets and result screenshots.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Resilience4j: Real-World Spring Boot 3 Circuit Breaker Cases

Third‑party API calls are common but introduce stability, performance, and security risks; without a circuit‑breaker, failures can block threads, exhaust resources, and crash the application. Implementing a circuit‑breaker ensures graceful degradation and protects core functionality.

Resilience4j is a lightweight fault‑tolerance library inspired by Netflix Hystrix and designed for functional programming. It offers decorators such as circuit‑breaker, rate‑limiter, retry, and bulkhead that can be composed on any functional interface, lambda, or method reference.

1. Dependency Management

<code>&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
  &lt;artifactId&gt;spring-cloud-starter-circuitbreaker-resilience4j&lt;/artifactId&gt;
&lt;/dependency&gt;</code>

2. RestTemplate Call Example

<code>@Service
public class CircuitService {
    private final RestTemplate restTemplate;
    private final CircuitBreakerFactory circuitBreakerFactory;

    public CircuitService(RestTemplate restTemplate, CircuitBreakerFactory circuitBreakerFactory) {
        this.restTemplate = restTemplate;
        this.circuitBreakerFactory = circuitBreakerFactory;
    }

    public Object remoteService(Integer id) {
        CircuitBreaker cb = this.circuitBreakerFactory.create("akk");
        return cb.run(() -> this.restTemplate.getForObject(
                "http://localhost:8088/demos/info/{id}", Map.class, id),
            ex -> Map.ofEntries(
                Map.entry("code", -1),
                Map.entry("message", ex.getMessage())));
    }
}
</code>

The default timeout is 1 s; because the simulated endpoint sleeps for 3 s, the fallback response (code ‑1) is returned.

3. WebClient Call Example (Reactive)

<code>private final WebClient webClient;
private final ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory;

public CircuitBreakerService(WebClient webClient, ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory) {
    this.webClient = webClient;
    this.reactiveCircuitBreakerFactory = reactiveCircuitBreakerFactory;
}

public Mono<Map> reactiveInvoke(Integer id) {
    return webClient.get()
        .uri("/demos/info/{id}", id)
        .retrieve()
        .bodyToMono(Map.class)
        .transform(it -> this.reactiveCircuitBreakerFactory.create("akk")
            .run(it, ex -> Mono.just(Map.ofEntries(
                Map.entry("code", -1),
                Map.entry("message", ex.getMessage())))));
}
</code>

The result image shows the same fallback behavior as the RestTemplate example.

4. Annotation‑Based Circuit Breaker

<code>@CircuitBreaker(name = "a-info", fallbackMethod = "infoFallback")
public Map<String, Object> info(Integer id) {
    if (id == -1) {
        throw new RuntimeException("非法数字");
    }
    return this.restTemplate.getForObject("http://localhost:8088/demos/info/{id}", Map.class, id);
}

public Map<String, Object> infoFallback(Integer id, Throwable e) {
    return Map.of("code", -1, "message", e.getMessage(), "args", id);
}
</code>

Configuration in application.yml :

<code>resilience4j:
  circuitbreaker:
    instances:
      a-info:
        minimum-number-of-calls: 10
</code>

5. Circuit Breaker Creation and Configuration

Calling CircuitBreakerFactory#create creates a CircuitBreaker instance. The run method requires a Supplier (the protected call) and a Function (the fallback). If no fallback is needed, it can be omitted.

6. Default and Custom Configuration

Default settings can be overridden in the configuration file. For example, extending the timeout to 4 s:

<code>resilience4j:
  timelimiter:
    configs:
      default:
        timeout-duration: 4s
</code>

After applying this change, a request that previously timed out at 1 s now succeeds within the 3 s simulated delay, as shown in the following screenshot.

7. Programmatic Custom Configuration for Specific Instances

<code>@Component
public class ReactiveCircuitBreakerCustomizer implements Customizer<ReactiveResilience4JCircuitBreakerFactory> {
    @Override
    public void customize(ReactiveResilience4JCircuitBreakerFactory factory) {
        Consumer<Resilience4JConfigBuilder> config = cb -> {
            cb.circuitBreakerConfig(CircuitBreakerConfig.custom().build());
            cb.timeLimiterConfig(TimeLimiterConfig.custom()
                .timeoutDuration(Duration.ofSeconds(4))
                .build());
        };
        factory.configure(config, "akk", "a2");
    }
}
</code>

These examples demonstrate how to integrate Resilience4j into Spring Boot 3 applications, apply circuit‑breaker patterns with both imperative and reactive APIs, and fine‑tune behavior through annotations, YAML, or programmatic customizers.

JavaBackend DevelopmentSpring Bootcircuit-breakerResilience4j
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.