Spring Cloud 斷路器

Spring Cloud 斷路器為不同的斷路器實作提供了一個抽象層。它提供了一致的 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 方法接受 SupplierFunctionSupplier 是您要包裝在斷路器中的程式碼。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)