Spring Cloud 斷路器
Spring Cloud 斷路器為不同的斷路器實作提供了一個抽象層。它提供了一致的 API 供您在應用程式中使用,讓身為開發人員的您可以選擇最適合您應用程式需求的斷路器實作。
核心概念
要在您的程式碼中建立斷路器,您可以使用 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
和 Function
。Supplier
是您要包裝在斷路器中的程式碼。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
方法接受 Mono
或 Flux
並將其包裝在斷路器中。您可以選擇性地設定後備 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)