1. 简介
第三方接口调用在应用中十分常见,它使得不同系统和服务能够相互通信、共享数据和功能。然而,这种跨系统的交互也带来了一系列风险,特别是在接口稳定性、性能和安全性方面。因此,在调用第三方接口时,必须做好熔断降级策略,以确保系统的稳健性和可用性。
在第三方接口调用中,熔断降级的作用尤为重要。当第三方接口出现故障或响应缓慢时,如果没有熔断降级机制,调用方可能会长时间等待响应,甚至耗尽系统资源,导致整个应用崩溃。而通过熔断降级,调用方可以在检测到异常情况时迅速切断连接,避免进一步损失,并通过降级策略确保核心功能的稳定运行。
2. Resilience4j简介
Resilience4j是一个轻量级容错框架,设计灵感来源于Netflix 的Hystrix框架,为函数式编程所设计。
Resilience4j 提供了一组高阶函数(装饰器),包括断路器,限流器,重试,隔离,可以对任何的函数式接口,lambda表达式,或方法的引用进行增强,并且这些装饰器可以进行叠加。这样做的好处是,你可以根据需要选择特定的装饰器进行组合。
3. 实战案例
3.1 依赖管理
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId></dependency>目标接口准备
@GetMapping("/info/{id}")publicObject info(@PathVariable("id") Integer id, @RequestParam Map<String, Object> params) throws Exception { TimeUnit.SECONDS.sleep(3) ; return Map.of("code", 0, "message", "success") ;}3.2 RestTemplate接口调用
@Servicepublic class CircuitService{
private final RestTemplate restTemplate ; private final CircuitBreakerFactory circuitBreakerFactory ;
public CircuitService(RestTemplate restTemplate, CircuitBreakerFactory circuitBreakerFactory) { this.restTemplate = restTemplate ; this.circuitBreakerFactory = circuitBreakerFactory ; }
public Object remoteService(Integer id) { CircuitBreaker create = this.circuitBreakerFactory .create("akk") ; return create.run(() -> this.restTemplate.getForObject("http://localhost:8088/demos/info/{id}", Map.class, id) , ex -> Map.ofEntries( entry("code", -1), entry("message", ex.getMessage()) )) ; }}CircuitBreakerFactory#create 会创建 CircuitBreaker 的类的实例。运行方法需要一个 Supplier 和一个 Function。Supplier是要封装到断路器中的代码。Function是断路器跳闸时运行的后备函数。函数传递的是导致触发回退的Throwable。如果不想提供回退函数,可以选择将其排除在外。
请求结果

默认超时时间是1s,而上面我们的接口模拟了3s耗时,所以这里返回的是fallback降级后的输出。
3.3 WebClient接口调用
WebClient是非阻塞,响应式的远程接口调用,那么我们对应使用的断路器工厂是ReactiveResilience4JCircuitBreakerFactory。我们只需要引入spring-boot-starter-webflux依赖即可。
private final WebClient webClient ; private final ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory ;
public CircuitBreakerService(WebClient webClient, ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory) { this.webClient = webClient ; this.reactiveCircuitBreakerFactory = reactiveCircuitBreakerFactory ;}接口调用
public Mono<Map> reactiveInvoke(Integer id) { return webClient.get() .uri("/demos/info/{id}", id) .retrieve().bodyToMono(Map.class) .transform(it -> this.reactiveCircuitBreakerFactory.create("akk").run(it, ex -> Mono.just(Map.ofEntries(entry("code", -1), entry("message", ex.getMessage()))))) ;}与上面RestTemplate错误差不多。
以上就是远程接口调用中如何应用Circuit Breaker,接下来将详细的讲解上面看到的CircutBreaker的创建。
3.4 基于注解
我们还可以通过注解+配置的方式,实现接口的熔断。
@CircuitBreaker(name = "a-info", fallbackMethod = "infoFallback")public Map<String, Object> info(Integer id) { if (id == -1) { throw new RuntimeException("非法数字") ; } return this.restTemplate.getForObject("http://localhost:8088/demos/info/{id}", Map.class, id) ;}public Map<String, Object> infoFallback(Integer id, Throwable e) { return Map.of("code", -1, "message", e.getMessage(), "args", id) ;}配置文件
resilience4j: circuitbreaker: instances: a-info: minimum-number-of-calls: 10通过注解+配置的方式能加灵活的管理。
3.5 断路器创建
在上面的示例中我们没有对CircuitBreaker做任何的配置,直接通过CircuitBreakerFactory#create创建实例。接下来以Resilience4JCircuitBreakerFactory为例进行配置说明:
修改配置默认
我们可以对不同的实例进行不同的配置也可以统一使用默认的配置。在上面的案例中就是使用的默认的配置。而默认的配置,我们可以在配置文件中进行修改
resilience4j: timelimiter: configs: default: timeout-duration: 4s超时时间设置为4s,而在上面我们的目标接口模拟耗时3s,这样配置后,我们再次请求接口

编程配置具体实例
除了上面的默认配置外,我们还可以对具体的实例进行配置
@Componentpublic class ReactiveCircuitBreakerCustomer implementsCustomizer<ReactiveResilience4JCircuitBreakerFactory> {
@Override public void customize(ReactiveResilience4JCircuitBreakerFactory tocustomize){ Consumer<Resilience4JConfigBuilder> customer = cb -> { cb.circuitBreakerConfig(CircuitBreakerConfig.custom().build()) ; cb.timeLimiterConfig(TimeLimiterConfig.custom() .timeoutDuration(Duration.ofSeconds(4)) .build()) ; }; tocustomize.configure(customer , "akk", "a2"); }}通过上面的配置也能针对具体的实例id进行配置。