avatar

SLHAF's blog

SLHAF的个人博客

  • 首页
  • 分类
  • 标签
  • 归档
  • 友链
主页 day_1 分布式入门: OpenFeign
文章

day_1 分布式入门: OpenFeign

发表于 28天前 更新于 26天前
作者 slhaf
29~37 分钟 阅读

OpenFeign

依赖导入

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

声明式实现与远程调用

要启用OpenFeignClient的依赖注入,需要先在Application启动类上加上@EnableFeignClients注解。

用法示例:

@FeignClient(value = "service-order")
public interface FeignOrderClient {
    @GetMapping("/order/{id}")
    OrderData getOrder(@PathVariable("id") int id);
}

@FeignClient注解中填入服务名称时,将自行查找在配置中心注册过的服务,可以通过MVC的Mapping注解发送请求;也可以再加上url属性及对应的值,此时将向该地址发送请求,可以调用第三方API。在方法中也可以通过@RequestParam、@RequestBody、@RequestHeader等对参数进行注解,声明对应的请求参数。

超时控制

FeignClient默认的的读取超时为60s,连接超时为10s.也可以通过在配置文件中设置形如下方的配置示例进行调整:

spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            logger-level: full
            connectTimeout: 1000
            readTimeout: 3000
          service-order:
            logger-level: full
            connect-timeout: 2000
            read-timeout: 5000

其中config下的default为可指定的FeignClient的默认配置,也可以通过类似service-order的键来对指定的client进行配置,这里与@FeignClient(value = "service-order")中的value一致,也可以是属性contextId,那此时注解就变成了@FeignClient(value = "service-order", contextId="xxxx")

重试配置

OpenFeign提供了重试器的配置,可以在配置文件中配置,也可以通过注册相应的Bean对象来为FeignClient提供重试器。

通过配置文件:

spring.cloud.openfeign.client.config.default.retryer=feign.Retryer.Default
spring.cloud.openfeign.client.config.service-order.retryer=feign.Retryer.Default

通过@Bean注解:

@Configuration
public class ProductConfiguration {

    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
    
    @Bean
    Retryer retryer(){
        return new Retryer.Default();
    }
}

Retryer提供的Default类也可以传递重试的配置参数:

public Default() {
  this(100, SECONDS.toMillis(1), 5);
}
public Default(long period, long maxPeriod, int maxAttempts) {
  this.period = period;
  this.maxPeriod = maxPeriod;
  this.maxAttempts = maxAttempts;
  this.attempt = 1;
}

拦截器

OpenFeign也提供了对于请求或响应的不同拦截器。需实现RequestInterceptor接口

public class XTokenRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        template.header("X-Token", "123456");
    }
}

如果要投入使用,可以在配置文件中添加配置针对特定客户端启用:

spring:
  cloud:
    openfeign:
      client:
        config:
          service-order:
            request-interceptors:
              - work.slhaf.product.interceptor.XTokenRequestInterceptor

也可以在拦截器的实现类上加上@Component注解,容器会自动发现拦截器实例

Fallback兜底返回

当借助OpenFeign进行的远程调用出错/超时时,有时我们会希望返回一些默认值以便出错时流程也能够正常进行,而不是输出错误信息,为此OpenFeign也提供了Fallback机制。我们可以通过实现声明式实现与远程调用一节中提到的用于发送请求的FeignClient中的请求方法,在其中实现兜底逻辑并返回。

比如:

@Component
public class FeignOrderClientFallback implements FeignOrderClient {
    @Override
    public OrderData getOrder(int id) {
        OrderData orderData = new OrderData();
        orderData.setId(0);
        orderData.setName("fail");
        return orderData;
    }
}

同样需要加上@component注解,同时也需要在相应的FeignClient中指定Fallback用到的类:

@FeignClient(value = "service-order",fallback = FeignOrderClientFallback.class)
public interface FeignOrderClient {
    @GetMapping("/order/{id}")
    OrderData getOrder(@PathVariable("id") int id);
}

但这个行为需要配合sentinel使用,需要在配置文件中开启熔断功能,即加上以下配置:

feign:
  sentinel:
    enabled: true

sentinel翻译过来是哨兵来着,不过两个也确实都挺形象的

额外思考

在课程提到Fallback兜底返回时,我想到的是应该也能够使用OpenFeign响应拦截器实现,或者说try-catch也能实现,但OpenFeign为什么又提供了一种机制?它的实现是封装了响应拦截器、还是异常捕获吗?还是说新增了一些东西使得这种兜底机制更合适、安全?

问了一下ChatGPT,这是它的回答:

非常棒的问题,问到了OpenFeign Fallback 机制的设计本质,这也是你从“使用者”走向“理解者”的关键一步。

我们来拆解这个问题,从多个维度看清楚:


🔍 1. 你提到的三种方式是并列的吗?

你提到的三种方案:

方法能否做到兜底?优点局限
try-catch✅灵活、细粒度控制需要手动写所有异常处理逻辑,容易遗漏;不集中
响应拦截器(RequestInterceptor、ResponseInterceptor)❌(无法兜底返回)可统一处理 header、日志等无法替代 fallback,仅能拦截请求或响应
OpenFeign Fallback✅自动触发,和调用接口解耦需依赖容器注入、可能影响调试透明性

所以回答第一个小问题:

❗ OpenFeign 的 Fallback 并不是“多此一举”,而是“异常处理职责的一种优雅集中方案”。


⚙️ 2. 那它是怎么实现的?真的用了拦截器 or try-catch?

我们来看 OpenFeign 的机制实现,分为两个阶段:

✅ Feign 默认机制:异常抛出

Feign 的默认行为是:请求失败就抛异常,比如连接失败、5xx 等,会抛出如 RetryableException、FeignException。

✅ Fallback 机制触发条件:

当你在 @FeignClient 注解中配置了 fallback = Xxx.class 时:

  • Spring Cloud 会用 Hystrix(旧)或 Sentinel(新)等“熔断框架”对 Feign 的代理对象进行包装。
  • 如果远程调用失败、熔断器打开、异常触发(包括运行时异常/连接失败等),
    它会自动走到 fallback 实例中定义的实现方法。

✅ 底层实现原理(以 Sentinel 为例):

  1. Feign 客户端通过 SentinelInvocationHandler 包装。

  2. 内部逻辑大致为:

    try {
        // 发起真正的 HTTP 请求
        return methodHandler.invoke(...);
    } catch (Throwable t) {
        // 如果 fallback 存在,调用 fallback 实现的方法
        return fallbackMethodHandler.invoke(...);
    }
    
  3. fallback 方法由 Spring IOC 提供(即你 @Component 的那一类)


🔐 3. 为啥 OpenFeign 推荐使用 fallback,而不是 try-catch?

🔸 try-catch 的问题:

  • 你要在每次调用都写 try-catch,重复又容易出错。
  • 不利于全局熔断、指标收集(比如你想统计某服务的失败率?)
  • 不容易统一处理不同接口的异常策略(兜底值?返回空?默认对象?提示?)

🔸 fallback 的优势:

  • 集中处理,每个接口方法只写一次兜底逻辑
  • 与接口定义在一起,调用端逻辑干净
  • 更适合配合熔断框架自动接管失败流程,安全、可控、可扩展

📌 小结一句话

Fallback 是在“你无法预知服务是否正常”场景下的一种声明式安全网,它基于底层异常机制 + 动态代理封装 + 熔断框架的组合,不是简单的 try-catch 或拦截器替代品。

总结:

尽管我们可以用 try-catch 捕获远程调用异常,OpenFeign 仍推荐使用 fallback 机制。其原因在于 fallback 是基于 Spring Cloud + 熔断框架(如 Sentinel)的高级封装,它统一了异常处理逻辑、增强了系统健壮性,也更适合分布式架构下的失败恢复策略。

与 try-catch 相比,fallback 更集中、解耦,且支持自动熔断触发;与拦截器不同,它处理的是请求失败的“后果”,而不是请求本身。因此,fallback 是面向“异常兜底”的最佳实践。

OpenFeign, 后端
分布式 Java 学习
许可协议:  CC BY 4.0
分享

相关文章

7月 10, 2025

day_1 分布式入门: OpenFeign

OpenFeign是Spring Cloud中的声明式HTTP客户端,通过@EnableFeignClients启用并配合@FeignClient注解实现远程服务调用。文章介绍了其依赖配置、超时控制(默认连接10s/读取60s)、重试机制(通过配置文件或Retryer Bean)、请求拦截器实现以及Fallback熔断机制(需结合Sentinel)。OpenFeign提供了集中式的异常处理方案,相比try-catch更优雅,支持通过接口实现兜底逻辑。这些特性使其成为分布式系统中服务调用的重要工具。

下一篇

day_0 分布式入门: 基本知识+Nacos基础

上一篇

day_2 分布式入门: Sentinel

最近更新

  • 为无头服务器配置带 GUI 的 Clash 客户端:基于 Xvfb + VNC 的解决方案
  • Manjaro/X11 环境下通过 bbswitch 关闭 NVIDIA 显卡以延长续航
  • 关于Bottles中同一容器内不同应用需要配置不同显卡方案的解决办法
  • day_3 分布式入门: Gateway
  • day_2 分布式入门: Sentinel

热门标签

Java 日常 分布式 Linux 学习 脚本 智能体 香橙派

目录

©2025 SLHAF's blog. 保留部分权利。

使用 Halo 主题 Chirpy