Spring Cloud Circuit Breaker
Spring Cloud 断路器为不同的断路器实现提供了一种抽象。它提供了一致的 API,可在应用程序中使用,令您这款们,作为开发人员,可以选择最适合您应用程序需要的断路器实现。
Core Concepts
要在代码中创建断路器,您可以使用 CircuitBreakerFactory API。当您在类路径上包含 Spring Cloud 断路器启动器时,会为您自动创建一个实现此 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。如果您不想提供备用方法,则可以选择将其排除在外。
Circuit Breakers In Reactive Code
如果类路径上有 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 Profiler,在断路器跳闸时将调用此函数,并且将传递导致失败的 Throwable。
Configuration
您可以通过创建 Customizer 类型 的 Bean 来配置断路器。Customizer 接口具有一个(名为 customize)方法,它采用要自定义的 Object。
有关如何自定义给定实现的详细信息,请参阅以下文档:
一些 CircuitBreaker`实现(例如 `Resilience4JCircuitBreaker)在每次调用 `CircuitBreaker#run`时都会调用 `customize`方法。这可能会效率低下。在这种情况下,可以使用 `CircuitBreaker#once`方法。对于在许多情况下调用 `customize`没有意义的情形(例如,在 consuming Resilience4j’s events的情况下),此方法非常有用。
以下示例展示了每个 io.github.resilience4j.circuitbreaker.CircuitBreaker 使用事件的方式。
Customizer.once(circuitBreaker -> {
circuitBreaker.getEventPublisher()
.onStateTransition(event -> log.info("{}: {}", event.getCircuitBreakerName(), event.getStateTransition()));
}, CircuitBreaker::getName)