多Feign客户端共享断路器:spring-cloud-starter-openfeign实现方法问询
当然可以实现!咱们完全能让这3个Feign客户端共用同一个Circuit Breaker实例,这样当外部组件宕机、请求失败达到熔断阈值时,所有关联的客户端都会直接触发降级逻辑,停止发送无效请求。下面结合Spring Cloud生态中推荐的Resilience4j Circuit Breaker来一步步实操:
1. 先把依赖备齐
首先需要引入OpenFeign和Resilience4j的starter依赖(如果用Maven的话):
<!-- OpenFeign核心依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- Resilience4j Circuit Breaker依赖(替代Hystrix,更活跃的维护) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId> </dependency>
2. 创建一个全局共享的Circuit Breaker实例
写个配置类,手动创建一个Circuit Breaker bean,给它指定一个唯一的名称(比如externalServiceCircuitBreaker),所有Feign客户端都会绑定这个实例:
import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.time.Duration; @Configuration public class SharedCircuitBreakerConfig { @Bean("externalServiceCircuitBreaker") public CircuitBreaker sharedCircuitBreaker() { // 自定义熔断规则,根据你的业务调整 CircuitBreakerConfig config = CircuitBreakerConfig.custom() .failureRateThreshold(50) // 10秒内50%请求失败就触发熔断 .waitDurationInOpenState(Duration.ofSeconds(30)) // 熔断后30秒再尝试恢复 .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.TIME_BASED) .slidingWindowSize(10) // 时间窗口内统计10次请求 .minimumNumberOfCalls(5) // 至少5次请求才开始计算失败率 .build(); return CircuitBreaker.of("externalServiceCircuitBreaker", config); } }
3. 让Feign客户端绑定到这个共享熔断实例
有两种常用方式,选适合你的就行:
方式一:逐个给Feign客户端方法加注解
在每个Feign客户端的方法(或者类)上使用@CircuitBreaker注解,指定我们刚才创建的共享熔断实例名称:
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; @FeignClient(name = "serviceA", url = "${external.service.url}") public interface ServiceAClient { @CircuitBreaker(name = "externalServiceCircuitBreaker", fallbackMethod = "fallbackForServiceA") @GetMapping("/api/serviceA") String getServiceAData(); // 降级方法,参数要和原方法匹配,最后可加Throwable接收异常 default String fallbackForServiceA(Throwable throwable) { return "Service A 降级提示:外部服务暂时不可用"; } }
同理,ServiceBClient和ServiceCClient也用同一个name = "externalServiceCircuitBreaker":
@FeignClient(name = "serviceB", url = "${external.service.url}") public interface ServiceBClient { @CircuitBreaker(name = "externalServiceCircuitBreaker", fallbackMethod = "fallbackForServiceB") @GetMapping("/api/serviceB") String getServiceBData(); default String fallbackForServiceB(Throwable throwable) { return "Service B 降级提示:外部服务暂时不可用"; } }
方式二:全局配置所有Feign客户端默认用这个熔断实例
如果不想每个Feign客户端都加注解,可以写个全局Feign配置类,让所有客户端默认绑定共享熔断实例:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import feign.Feign; import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.feign.Resilience4jFeign; @Configuration public class GlobalFeignCircuitBreakerConfig { private final CircuitBreaker sharedCircuitBreaker; // 注入咱们创建的共享熔断实例 public GlobalFeignCircuitBreakerConfig(CircuitBreaker sharedCircuitBreaker) { this.sharedCircuitBreaker = sharedCircuitBreaker; } @Bean public Feign.Builder feignBuilder() { return Resilience4jFeign.builder() .circuitBreaker(sharedCircuitBreaker); } }
然后在每个FeignClient上指定这个配置类:
@FeignClient(name = "serviceA", url = "${external.service.url}", configuration = GlobalFeignCircuitBreakerConfig.class) public interface ServiceAClient { // 方法定义... }
或者想让所有Feign客户端默认生效,直接在application.yml里配置:
spring: cloud: openfeign: circuitbreaker: enabled: true # 开启Feign的熔断支持 client: default-config: default config: default: configuration: com.your.package.GlobalFeignCircuitBreakerConfig # 替换成你的配置类路径
4. 验证效果
当外部组件宕机后,只要任意一个Feign客户端的请求失败达到咱们配置的熔断阈值(比如50%失败率),这个共享的Circuit Breaker就会切换到Open状态,此时所有绑定它的Feign客户端都会直接触发降级逻辑,不再发送请求到外部组件。等30秒(咱们配置的等待时间)后,熔断会进入Half-Open状态,尝试发送少量请求测试服务是否恢复,如果恢复就关闭熔断,否则继续保持Open状态。
额外说明
- 如果还在使用Hystrix(虽然已经进入维护模式),也可以通过指定同一个
groupKey来实现共享熔断,比如在@HystrixCommand中设置groupKey = "externalServiceGroup",多个Feign客户端会共用这个组的熔断规则。 - 降级方法的参数列表必须和原方法一致,最后可以追加一个
Throwable参数来接收异常信息,否则会抛出方法匹配错误。 - 熔断规则的参数(失败率、等待时间等)一定要根据你的业务场景调整,比如核心服务可以把失败率阈值设低一点,等待时间短一点。
内容的提问来源于stack exchange,提问作者Jeff

