Circuit Breaker com Resilience4j no Spring Boot: tutorial passo a passo
Por John Pires · 16 de março de 2026

Circuit Breaker com Resilience4j no Spring Boot: tutorial passo a passo
1) O que é e por que importa
O padrão circuit breaker é uma técnica madura de engenharia de software para controlar falhas em sistemas distribuídos. Em microservices, quando um serviço downstream demora ou falha repetidamente, manter requisições abertas só agrava a latência e consome recursos. Um circuit breaker detecta falhas repetidas e corta (abre) a comunicação por um tempo, permitindo que o downstream se recupere.
Resilience4j é uma biblioteca leve e modular, feita para Java 8+, que implementa padrões de resiliência como circuit breaker, retry, rate limiter e bulkhead. Integrada ao Spring Boot, ela fornece anotações, configuração programática e métricas.
Por que isso importa para quem começa: sem circuit breaker, um serviço problemático pode causar efeito dominó (cascade failure). Com ele você protege recursos e ganha previsibilidade.
Analogia simples: pense em um fusível elétrico. Se muita corrente passa (falhas / latência), o fusível desarma para proteger o circuito. O circuit breaker faz isso para chamadas remotas: detecta padrões ruins e interrompe as chamadas até que as condições melhorem.
Prática: nunca conecte um cliente HTTP diretamente a muitos recursos externos sem uma camada de proteção — circuit breakers são essa camada.
2) Conceitos fundamentais com analogias
2.1 Estados do circuit breaker
Um circuit breaker típico tem 3 estados:
- Closed: tudo normal; requests passam e contador de falhas é observado.
- Open: o circuito está aberto; requests falham rapidamente ou caem para um fallback.
- Half-Open: teste — permite algumas requisições para verificar se o downstream voltou.
Analogia: um guarda em uma ponte que, ao ver excesso de peso (falhas), fecha a ponte (open). Depois de um tempo, abre um corredor de teste (half-open) para checar se está seguro voltar a abrir totalmente (closed).
2.2 Métricas e limiares
O breaker usa métricas: número de chamadas, taxa de falhas, janelas de tempo. Configure um limiar (por exemplo, >50% de falha em 30s) para disparar o open. Resilience4j usa SlidingWindow por padrão.
Escolha limiares com base em testes e na criticidade do serviço. Limiares muito agressivos causam flapping; limiares muito tolerantes não protegem seu sistema.
3) Passo a passo com código comentado
3.1 Dependências e configuração básica
Contexto: primeiro passo é adicionar as dependências do Resilience4j e Spring Boot ao seu projeto Maven. A seguir um pom.xml mínimo com as dependências necessárias.
<!-- pom.xml: dependências essenciais -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-micrometer</artifactId>
</dependency>
</dependencies>
O que faz: adiciona Spring Web e Resilience4j com integração Spring Boot. O after: você terá as anotações e beans necessários para usar circuit breaker via @CircuitBreaker e para expor métricas via Micrometer.
3.2 Configuração via application.yml
Contexto: configure nomes, janelas e limiares no application.yml para controlar comportamento do breaker.
# application.yml: configuração do resilience4j
resilience4j:
circuitbreaker:
instances:
remoteServiceCB:
registerHealthIndicator: true
slidingWindowType: TIME_BASED
slidingWindowSize: 10
minimumNumberOfCalls: 5
failureRateThreshold: 50
waitDurationInOpenState: 10s
permittedNumberOfCallsInHalfOpenState: 3
O que faz: define um instance chamado remoteServiceCB com janela baseada em tempo, limiar de 50% e espera de 10s. O after: Resilience4j passa a aplicar essas regras quando o nome do circuit breaker for usado.
3.3 Anotações e fallback
Contexto: exemplo de serviço que faz chamada HTTP para um serviço externo; usamos @CircuitBreaker para aplicar proteção e um método de fallback que entrega resposta padrão.
package com.exemplo.service;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class RemoteService {
private final RestTemplate restTemplate = new RestTemplate();
// Aplica o circuit breaker com o nome configurado em application.yml
@CircuitBreaker(name = "remoteServiceCB", fallbackMethod = "fallbackGet")
public String getRemoteData() {
// Chamada que pode falhar: tempo limite, 5xx, etc.
return restTemplate.getForObject("http://localhost:8081/api/remote", String.class);
}
// Método de fallback: recebe a exceção original como último parâmetro
public String fallbackGet(Exception ex) {
return "fallback-response"; // resposta simples e determinística
}
}
O que faz: quando a chamada falha repetidamente, o circuit breaker abre e a biblioteca redireciona as chamadas para fallbackGet. O after: você evita chamadas bloqueantes para o serviço instável e entrega uma resposta previsível.
3.4 Erros comuns e debugging
Contexto: quem está começando costuma ver o circuit breaker sem efeito ou com comportamento inesperado. Aqui listamos armadilhas frequentes e como diagnosticá-las.
- Não configurar o nome do circuit breaker corretamente: o nome passado em @CircuitBreaker precisa existir no application.yml ou haverá comportamento default.
- Usar RestTemplate sem timeouts: se não houver timeout, a chamada pode pendurar e distorcer as métricas.
- Não ajustar
minimumNumberOfCalls: se for maior que o número de chamadas em uma janela, o breaker nunca calcula taxa de falha. - Esquecer de tratar exceções específicas: por padrão, Resilience4j considera exceções lançadas. Se o seu cliente retorna respostas 500 sem lançar exception, o breaker não contará como falha.
Dica: habilite logs e exponha métricas Micrometer para ver estados e contadores do breaker em runtime.
Depois: para debugging, inspecione beans CircuitBreakerRegistry e use endpoints /actuator/metrics (quando configurado) para ver as métricas.
4) Exemplo prático completo
Contexto: vamos construir um mini-projeto com Controller que consome RemoteService e retorna a resposta ao cliente. Inclui fallback, configuração e um pequeno test manual (curl).
4.1 Estrutura do projeto
Arquitetura mínima:
- Application (main)
- Controller (exposes /api/data)
- Service (chama serviço externo com @CircuitBreaker)
- application.yml com configuração do CB
Crie um projeto Spring Boot padrão com as dependências já mostradas. A seguir os arquivos Java essenciais.
4.2 Código: Application e Controller
Contexto: classe main e controller que expõe o endpoint local que depende do RemoteService.
package com.exemplo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
// Controller
package com.exemplo.web;
import com.exemplo.service.RemoteService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DataController {
private final RemoteService remoteService;
public DataController(RemoteService remoteService) {
this.remoteService = remoteService;
}
@GetMapping("/api/data")
public String getData() {
return remoteService.getRemoteData();
}
}
O que faz: o controller chama o serviço que possui circuit breaker. Quando o downstream falha, o controller recebe a resposta de fallback.
4.3 Código: RemoteService com RestTemplate configurado
Contexto: RestTemplate com timeout para evitar chamadas pendentes que estragam métricas.
package com.exemplo.service;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class RemoteService {
private final RestTemplate restTemplate;
public RemoteService() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(2000); // 2s connect timeout
factory.setReadTimeout(3000); // 3s read timeout
this.restTemplate = new RestTemplate(factory);
}
@CircuitBreaker(name = "remoteServiceCB", fallbackMethod = "fallbackGet")
public String getRemoteData() {
return restTemplate.getForObject("http://localhost:8081/api/remote", String.class);
}
public String fallbackGet(Exception ex) {
// Aqui podemos logar e retornar uma resposta simples
System.err.println("Fallback acionado: " + ex.getClass().getSimpleName() + " -> " + ex.getMessage());
return "{\"status\":\"fallback\",\"data\":null}";
}
}
O que faz: solicita ao serviço remoto com timeouts configurados; em caso de falhas repetidas, Resilience4j chama o fallback. O after: o endpoint /api/data continuará respondendo, evitando timeouts longos para o cliente.
4.4 Testando manualmente e observando comportamento
Contexto: para testar, inicialmente execute um servidor remoto simples (pode ser outro Spring Boot na porta 8081) que retorna 500 quando solicitado. Em seguida, faça múltiplas requisições ao seu endpoint /api/data e observe o comportamento do circuit breaker.
Comandos curl para testar:
# Requisições que devem falhar e acionar o CB
for i in {1..10}; do curl -s http://localhost:8080/api/data; echo; sleep 1; done
# Depois de aberto, as respostas virão do fallback imediatamente
curl -s http://localhost:8080/api/data
O que acontece: nas primeiras falhas, o CB contabiliza as chamadas. Se o limiar for atingido, ele abre e passa a chamar o fallback sem tentar o downstream até que o tempo de espera expire. Em half-open ele testará algumas chamadas.
4.5 Observabilidade
Contexto: conecte métricas ao Prometheus/Grafana ou use /actuator/metrics para consultar metrics do Resilience4j. Exemplo de fluxo: habilitar micrometer e consultar metricas como resilience4j.circuitbreaker.state.
Dica prática: adicione logs no fallback e use CircuitBreakerRegistry para inspecionar estado via JMX ou endpoints de debug.
5) Próximos passos para aprofundar
5.1 Padrões complementares
Para construir resiliência real, combine circuit breaker com:
- Retry: repetir com backoff controlado para falhas transitórias.
- Rate limiting: proteger seu serviço de overload.
- Bulkhead: isolar recursos para evitar falhas em cascata.
Resilience4j oferece todos esses módulos e eles interagem bem quando combinados de forma consciente.
5.2 Testes e chaos engineering
Inclua testes que simulam latência e falhas (wiremock, MockWebServer) para validar configuração do breaker. Considere práticas de chaos engineering em ambiente controlado para validar comportamento em produção.
Exemplo: escrever testes de integração que simulam respostas 500 e confirmam que o fallback foi acionado e que o CB trocou de estado.
5.3 Performance e virtual threads
Se usar Java 19+ com virtual threads, prefira clientes HTTP não bloqueantes (WebClient) ou ajuste ThreadPools. O circuit breaker atua sobre a lógica, mas recursos de threads e I/O impactam as métricas. Teste com carga real.
Conclusão prática
Implementar circuit breaker com Resilience4j no Spring Boot é direto: adicione dependências, configure instâncias no application.yml, anote métodos com @CircuitBreaker e implemente fallbacks determinísticos. O ponto-chave para iniciantes é: configure timeouts, defina limiares realistas e exponha métricas para monitoramento.
Para começar rápido: 1) adicione Resilience4j, 2) configure um instance com slidingWindow e waitDuration, 3) envolva chamadas remotas com @CircuitBreaker e um fallback simples, 4) monitore com /actuator/metrics. Isso reduz o risco de falhas em cascata e aumenta a previsibilidade do seu serviço.
Resumo técnico: circuit breaker não é substituto para um design robusto; é uma ferramenta para mitigar falhas. Combine com retry, bulkhead e observabilidade para sistemas distribuídos saudáveis.
Checklist final:
- Timeouts HTTP configurados
- Nome do breaker consistente entre anotações e config
- Mínimo de chamadas para observar falhas
- Fallback determinístico e simples
- Métricas e logs habilitados
Implementação prática e instrumentada é o melhor caminho para aprender: crie um serviço de teste, force falhas e observe como o circuit breaker protege seu ecossistema.
Assuntos: Java, spring-boot, resilience4j, circuit-breaker, microservices
Leia também
Evitar exaustão de conexões JDBC ao usar Virtual Threads no Spring Boot
Evite exaustão do pool JDBC ao adotar virtual threads no Spring Boot: identifique o erro comum (criar virtual threads sem limites) e aplique padrões práticos…
Idempotência em APIs Spring Boot: chaves, Redis e exemplo passo a passo
Implementação prática de idempotência em APIs Spring Boot usando chaves e Redis. Tutorial passo a passo com configuração, interceptor, controller e dicas para…
Instrumentando Spring Boot com OpenTelemetry: traces, métricas e logs passo a passo
Guia prático para instrumentar Spring Boot com OpenTelemetry: do ambiente à instrumentação manual e via javaagent, traces, métricas e correlação de logs com…
Processando grandes consultas JPA sem OOM: Stream, fetchSize e batches
Técnicas práticas para processar grandes consultas JPA sem OOM: use stream, ajuste fetchSize e processe em batches com limpeza do persistence context para…
Virtual Threads no Spring Boot: migrar controllers bloqueantes, JPA e tuning do HikariCP
Guia prático para migrar controllers bloqueantes e JPA para virtual threads no Spring Boot, com exemplos reais, setup do HikariCP, armadilhas e padrões para…
Outbox transacional com Spring Boot, JPA e Kafka — implementação prática
Implementação prática do padrão Outbox com Spring Boot, JPA e Kafka: gravação atômica de eventos, poller confiável, idempotência do consumidor e técnicas para…