Spring Cloud 断路器
Spring Cloud 断路器为不同的断路器实现提供了一个抽象。它提供了一个一致的 API 供您的应用程序使用,让您(开发者)可以选择最适合您应用程序需求的断路器实现。
核心概念
要在代码中创建断路器,可以使用`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`。如果不想提供回退,可以选择不包含回退。
响应式代码中的断路器
如果 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)