Skip to content

Spring Boot Circuit Breaker — Complete Implementation Guide

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Spring Boot Circuit Breaker. We cover key concepts, practical examples, and best practices to help you master this topic.

Spring Boot circuit breakers using Resilience4j provide annotation-driven circuit breaking, declarative fallback methods, and seamless integration with Spring's metrics and Actuator systems.

What You'll Learn

By the end of this tutorial, you will know how to configure Resilience4j in Spring Boot, annotate methods with @CircuitBreaker, implement fallback handlers, and monitor circuit state.

Why It Matters

Spring Boot is the most popular Java framework. Resilience4j is the recommended circuit breaker library for Spring Boot applications, replacing the deprecated Hystrix with better performance and more features.

Real-World Use

Durga Antivirus Pro's scanning API uses Spring Boot with Resilience4j circuit breakers around its malware signature lookup service, ensuring the scan endpoint degrades gracefully when the signature database is unreachable.

Spring Boot Circuit Breaker Learning Path

flowchart LR
  A[Best Practices] --> B[Spring Boot Circuit Breaker]
  B --> C[Resilience4j Config]
  B --> D[Fallback Methods]
  B --> E[Metrics Integration]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Adding Resilience4j Dependencies

Add the Resilience4j Spring Boot starter to enable annotation-based circuit breakers.

// build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-aop'
    implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.1.0'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
# application.yml
resilience4j:
  circuitbreaker:
    configs:
      default:
        sliding-window-size: 10
        minimum-number-of-calls: 5
        failure-rate-threshold: 50
        wait-duration-in-open-state: 30s
        permitted-number-of-calls-in-half-open-state: 3
        automatic-transition-from-open-to-half-open-enabled: true

Annotation-Based Circuit Breaker

The @CircuitBreaker annotation wraps any Spring bean method with circuit breaker logic.

@Service
public class FileScanService {
    private static final Logger log = LoggerFactory.getLogger(FileScanService.class);

    @CircuitBreaker(name = "signatureDatabase", fallbackMethod = "fallbackScan")
    public ScanResult scanFile(byte[] fileContent) {
        log.info("Scanning file via signature database");
        ResponseEntity<ScanResult> response = restTemplate.postForEntity(
            "https://signatures.dodatech.com/scan",
            fileContent,
            ScanResult.class
        );
        return response.getBody();
    }

    public ScanResult fallbackScan(byte[] fileContent, Throwable t) {
        log.warn("Signature database unavailable, using cached signatures", t);
        return ScanResult.cachedScan(fileContent);
    }
}

Configuring Multiple Circuit Breakers

Different downstream services need different circuit breaker configurations.

@Configuration
public class CircuitBreakerConfig {

    @Bean
    public Customizer<Resilience4JCircuitBreakerFactory> defaultConfig() {
        return factory -> {
            factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
                .circuitBreakerConfig(CircuitBreakerConfig.custom()
                    .slidingWindowSize(10)
                    .failureRateThreshold(50)
                    .waitDurationInOpenState(Duration.ofSeconds(30))
                    .build())
                .timeLimiterConfig(TimeLimiterConfig.custom()
                    .timeoutDuration(Duration.ofSeconds(5))
                    .build())
                .build());

            factory.configure(builder -> builder
                .circuitBreakerConfig(CircuitBreakerConfig.custom()
                    .slidingWindowSize(5)
                    .failureRateThreshold(30)
                    .waitDurationInOpenState(Duration.ofSeconds(60))
                    .build())
                .build(), "databaseService");
        };
    }
}

Monitoring with Actuator and Metrics

Resilience4j exposes circuit breaker metrics through Spring Boot Actuator.

@RestController
@RequestMapping("/health")
public class CircuitHealthController {

    private final CircuitBreakerRegistry registry;

    public CircuitHealthController(CircuitBreakerRegistry registry) {
        this.registry = registry;
    }

    @GetMapping("/circuits")
    public Map<String, String> getCircuitStates() {
        Map<String, String> states = new HashMap<>();
        registry.getAllCircuitBreakers().forEach(cb -> {
            states.put(cb.getName(), cb.getState().name());
        });
        return states;
    }
}

// GET /health/circuits
// {
//   "signatureDatabase": "CLOSED",
//   "databaseService": "OPEN",
//   "notificationService": "HALF_OPEN"
// }

Event-Driven State Transitions

React to circuit breaker state changes with event listeners.

@Component
public class CircuitBreakerEventListener {

    private static final Logger log = LoggerFactory.getLogger(CircuitBreakerEventListener.class);

    @EventListener
    public void onCircuitEvent(CircuitBreakerEvent event) {
        if (event.getEventType() == CircuitBreakerEvent.Type.STATE_TRANSITION) {
            log.warn("Circuit breaker '{}' transition: {} -> {}",
                event.getCircuitBreakerName(),
                event.getPreviousState(),
                event.getCurrentState());

            if (event.getCurrentState() == CircuitBreaker.State.OPEN) {
                notificationService.sendAlert("Circuit opened for: " + event.getCircuitBreakerName());
            }
        }
    }
}

Common Mistakes

  1. Forgetting the fallbackMethod parameter -- The @CircuitBreaker annotation requires a fallbackMethod that matches the method signature plus a Throwable parameter. Missing it causes startup errors.

  2. Using the same circuit breaker name for different services -- Each downstream service should have a uniquely named circuit breaker with its own configuration.

  3. Not configuring a TimeLimiter -- Without a TimeLimiter, a slow request blocks the thread until completion. Add a timeout to Fail Fast and trip the circuit.

  4. Placing @CircuitBreaker on private methods -- Spring AOP only works on public methods called from outside the class. Self-invocation bypasses the circuit breaker.

  5. Ignoring the exception type in fallback methods -- The fallback method receives the exception as a parameter. Log it and handle different exception types differently.

Practice Questions

  1. What dependency do you need to add for Resilience4j circuit breakers in Spring Boot 3? resilience4j-spring-boot3 with spring-boot-starter-aop.

  2. How do you configure different settings for different circuit breakers? Use the Factory.configure() method with a circuit breaker name list. Each name gets its own configuration.

  3. What does the sliding-window-size configuration control? The number of requests used to calculate the failure rate. A window size of 10 means the failure rate is calculated from the last 10 requests.

  4. Challenge: Implement a circuit breaker that automatically recovers and sends a notification when a circuit transitions to open state.

@Component
public class AutoRecoveringCircuitBreaker {
    private final CircuitBreakerRegistry registry;
    private final NotificationService notifications;

    public AutoRecoveringCircuitBreaker(
            CircuitBreakerRegistry registry,
            NotificationService notifications) {
        this.registry = registry;
        this.notifications = notifications;
        registerListeners();
    }

    private void registerListeners() {
        registry.getAllCircuitBreakers().forEach(cb -> {
            cb.getEventPublisher()
                .onStateTransition(event -> {
                    if (event.getStateTransition().getToState() == CircuitBreaker.State.OPEN) {
                        notifications.alert("Circuit opened: " + cb.getName());
                    }
                    if (event.getStateTransition().getToState() == CircuitBreaker.State.CLOSED) {
                        notifications.info("Circuit recovered: " + cb.getName());
                    }
                });
        });
    }
}

FAQ

What is the difference between Resilience4j and Hystrix?

Resilience4j is the modern replacement for Hystrix. It offers better performance, no Netflix dependencies, functional programming support, and is actively maintained.

Can I use Resilience4j without Spring Boot?

Yes. Resilience4j is a standalone library. The Spring Boot starter adds annotation support and auto-configuration, but you can use the core API directly.

How does Resilience4j handle thread isolation?

Unlike Hystrix, Resilience4j does not isolate threads by default. It uses semaphores for concurrency control. Use the bulkhead module for thread pool isolation.

What metrics does Resilience4j expose?

It exposes: state, failure rate, slow call rate, call count, failure count, slow call count, and call durations. All exposed via Micrometer.

How do I test circuit breakers with Resilience4j?

Use the CircuitBreakerRegistry to get the circuit breaker, then use its event publisher to assert on state transitions. You can also manually trip the circuit for testing.

Mini Project

Build a Spring Boot service with three circuit breakers for different downstream services (signature database, file storage, notification service), each with its own configuration, fallback, and monitoring endpoint.

@SpringBootApplication
@EnableCircuitBreaker
public class ScanningServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ScanningServiceApplication.class, args);
    }

    @Bean
    public CommandLineRunner demo(CircuitBreakerRegistry registry) {
        return args -> {
            registry.getAllCircuitBreakers().forEach(cb -> {
                System.out.println("Circuit: " + cb.getName()
                    + " Config: window=" + cb.getCircuitBreakerConfig().getSlidingWindowSize()
                    + " threshold=" + cb.getCircuitBreakerConfig().getFailureRateThreshold() + "%");
            });
        };
    }
}

What's Next

Now that you understand Spring Boot circuit breakers, build the complete circuit breaker project that combines everything you've learned into a production-ready implementation.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro