Spring Cloud 熔断器

Spring Cloud Circuit breaker 在不同的熔断器实现之间提供了一个抽象。它提供了一个一致的 API 供你在应用中使用,让你(开发者)能够选择最适合你应用需求的熔断器实现。

支持的实现

Spring Cloud 支持以下熔断器实现

核心概念

要在代码中创建熔断器,你可以使用 CircuitBreakerFactory API。当你在类路径中包含 Spring Cloud Circuit Breaker starter 时,会自动为你创建一个实现此 API 的 Bean。以下示例展示了如何使用此 API 的简单示例

@Service
public static class DemoControllerService {
	private RestTemplate rest;
	private CircuitBreakerFactory cbFactory;

	public DemoControllerService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
		this.rest = rest;
		this.cbFactory = cbFactory;
	}

	public String slow() {
		return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback");
	}

}

CircuitBreakerFactory.create API 会创建一个名为 CircuitBreaker 的类的实例。run 方法接受一个 Supplier 和一个 FunctionSupplier 是你要包装在熔断器中的代码。Function 是在熔断器跳闸时运行的回退逻辑。此函数会被传入导致回退触发的 Throwable。如果不想提供回退,可以选择排除它。

响应式代码中的熔断器

如果 Project Reactor 在类路径中,你也可以为你的响应式代码使用 ReactiveCircuitBreakerFactory。以下示例展示了如何做到这一点

@Service
public static class DemoControllerService {
	private ReactiveCircuitBreakerFactory cbFactory;
	private WebClient webClient;


	public DemoControllerService(WebClient webClient, ReactiveCircuitBreakerFactory cbFactory) {
		this.webClient = webClient;
		this.cbFactory = cbFactory;
	}

	public Mono<String> slow() {
		return webClient.get().uri("/slow").retrieve().bodyToMono(String.class).transform(
		it -> cbFactory.create("slow").run(it, throwable -> return Mono.just("fallback")));
	}
}

ReactiveCircuitBreakerFactory.create API 会创建一个名为 ReactiveCircuitBreaker 的类的实例。run 方法接受一个 MonoFlux,并将其包装在熔断器中。你可以选择性地提供一个回退 Function,如果熔断器跳闸,该函数将被调用,并被传入导致失败的 Throwable

配置

你可以通过创建类型为 Customizer 的 Bean 来配置你的熔断器。Customizer 接口有一个单独的方法(称为 customize),该方法接受一个 Object 用于定制。

有关如何定制给定实现的详细信息,请参阅以下文档

一些 CircuitBreaker 实现(例如 Resilience4JCircuitBreaker)在每次调用 CircuitBreaker#run 时都会调用 customize 方法。这可能效率低下。在这种情况下,你可以使用 CircuitBreaker#once 方法。这对于多次调用 customize 没有意义的场景很有用,例如在消费 Resilience4j 事件的情况下。

以下示例展示了每个 io.github.resilience4j.circuitbreaker.CircuitBreaker 消费事件的方式。

Customizer.once(circuitBreaker -> {
  circuitBreaker.getEventPublisher()
    .onStateTransition(event -> log.info("{}: {}", event.getCircuitBreakerName(), event.getStateTransition()));
}, CircuitBreaker::getName)