Spring Cloud 断路器
Spring Cloud Circuit Breaker 提供了跨不同断路器实现的抽象。它提供了一个一致的 API 供您在应用程序中使用,让您作为开发者能够选择最适合您应用需求的断路器实现。
支持的实现
Spring Cloud 支持以下断路器实现:
核心概念
要在代码中创建熔断器,你可以使用 CircuitBreakerFactory API。当你在类路径中包含 Spring Cloud Circuit Breaker 启动器时,会自动为你创建一个实现此 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)
Spring HTTP 服务客户端支持
Spring Cloud 通过以下配置器为 Spring HTTP Service Clients 集成提供支持:
-
CircuitBreakerRestClientHttpServiceGroupConfigurer -
CircuitBreakerWebClientHttpServiceGroupConfigurer
这些配置器为Spring HTTP 服务客户端组提供了断路器支持。
当使用 @HttpServiceFallbackAnnotation 配置回退类时,会添加 CircuitBreaker 适配器装饰器:- CircuitBreakerAdapterDecorator 与 RestClient 配合使用- ReactiveCircuitBreakerAdapterDecorator 与 WebClient 配合使用
你可以通过设置相应的属性来禁用 HTTP 服务客户端的 CircuitBreaker 集成:
-
对于阻塞式(
RestClient)客户端:spring.cloud.circuitbreaker.http-services.enabled=false -
对于响应式(
WebClient)客户端:spring.cloud.circuitbreaker.reactive-http-services.enabled=false
这将阻止 CircuitBreaker 装饰器被应用到基于接口的 HTTP 客户端组。
使用注解声明回退函数
回退机制通过在配置类上使用 @HttpServiceFallback 注解进行配置。该注解允许您声明:
-
后备实现类(通过
value指定) -
后备支持的服务接口(通过
forService指定,可选) -
后备适用的组(通过
forGroup指定,可选)
可以在同一个类上声明多个 @HttpServiceFallback 注解,这是通过 Java 的 @Repeatable 注解机制实现的。如果没有指定组,则回退适用于所有组,前提是这些组没有为给定的服务接口指定明确的每组回退。
回退类的解析遵循以下优先级顺序:
-
一个同时匹配
forService和forGroup的回退类 -
一个匹配
forService但没有forGroup的回退类(服务的全局回退) -
一个没有
forService或forGroup的回退类(组内所有服务或全局的默认回退)
示例
@HttpServiceFallback(value = DefaultFallbacks.class)
@HttpServiceFallback(value = GroupAndServiceSpecificFallbacks.class, service = {BillingService.class, ShippingService.class}, group = "billing")
public class MyFallbackConfig {
...
}
此配置将导致:
-
DefaultFallbacks用作所有未明确处理服务的全局后备方案 -
GroupAndServiceSpecificFallbacks仅用于"billing"组内的BillingService和ShippingService
-
回退类及其方法必须是
public的 -
回退方法不能使用
@HttpExchange注解进行标注
熔断器适配器的工作原理
适配器使用熔断器逻辑包装 @HttpExchange 方法调用。当触发降级时,会使用用户定义的降级类创建代理。通过匹配以下条件选择适当的降级方法:
-
一个具有相同名称和参数类型的方法,或
-
一个具有相同名称和参数类型,但前面带有一个
Throwable参数的方法(用于访问失败原因)
给定以下接口:
@HttpExchange("/test")
public interface TestService {
@GetExchange("/{id}")
Person test(@PathVariable UUID id);
@GetExchange
String test();
}
一个匹配的回退类可以是:
public class TestServiceFallback {
public Person test(UUID id);
public String test(Throwable cause);
}