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)