Spring Cloud 熔斷器
Spring Cloud Circuit breaker 在不同的熔斷器實現之間提供了一個抽象。它提供了一個一致的 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)