当前位置: 首页 > news >正文

[spring cloud] OpenFeign远程调用

1. OpenFeign 核心原理

用一句话总结:OpenFeign 是一个声明式的 HTTP 客户端,通过动态代理将接口方法映射为 HTTP 请求。

它的核心工作流程如下:

  1. 启动扫描:Spring Boot 启动时,@EnableFeignClients注解会扫描所有标有@FeignClient的接口。
  2. 动态代理 (Dynamic Proxy):Spring 会为这些接口生成动态代理对象(JDK Proxy),并注入到 Spring 容器中。
  3. 请求拦截:当你调用接口方法(如orderService.createOrder())时,代理对象拦截该调用。
  4. 构造请求:根据接口上的注解(@GetMapping,@PathVariable等),解析出 URL、Method、Headers、Body 等信息,构建一个 HTTP Request Template。
  5. 服务发现与负载均衡
  • Feign 拦截到请求后,通过服务名(Service Name)去 Nacos 查找可用的 IP 列表。
  • 结合Spring Cloud LoadBalancer(在 Boot 3.x 中替代了 Ribbon) 选择一个最佳实例。
  1. 发送请求:通过底层的 HTTP 客户端(默认是 JDKHttpURLConnection,生产环境通常替换为OkHttpApache HttpClient)发送真正的网络请求。
  2. 解码响应:拿到 HTTP 响应后,通过Decoder(通常是 Jackson) 将 JSON 字符串反序列化成你定义的 Java 对象。

2. Java 代码实战

假设场景:你的service-order(订单服务)需要调用service-stock(库存服务)来扣减库存。

第一步:引入依赖 (pom.xml)

service-order(消费者) 中添加 OpenFeign 和 负载均衡器依赖。
注意:Spring Boot 3.x (Spring Cloud 2022.x) 彻底移除了 Ribbon,必须确保有 LoadBalancer。

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency></dependencies>
第二步:开启 Feign (启动类)

service-order的启动类上添加注解。

@SpringBootApplication@EnableFeignClients// 开启 Feign 扫描publicclassOrderApplication{publicstaticvoidmain(String[]args){SpringApplication.run(OrderApplication.class,args);}}
第三步:编写 Feign 接口 (核心)

创建一个接口,这就相当于以前写的 Controller 的方法签名,但是这里没有方法体。

packagecom.example.order.feign;importcom.example.order.dto.StockDTO;// 假设有一个传输对象importorg.springframework.cloud.openfeign.FeignClient;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestParam;// name: 指定要调用的 Nacos 服务名称 (非常重要,必须匹配)// path: 可选,如果对方 Controller 类上有 @RequestMapping("/stock"),这里可以统一加@FeignClient(name="service-stock",path="/stock")publicinterfaceStockFeignClient{/** * 查询库存 * 对应 GET http://service-stock/stock/{id} */@GetMapping("/{id}")StockDTOgetById(@PathVariable("id")Longid);/** * 扣减库存 * 对应 POST http://service-stock/stock/deduct?count=xxx */@PostMapping("/deduct")Stringdeduct(@RequestParam("count")Integercount);}
第四步:在业务代码中使用

OrderService中直接注入接口使用,就像调用本地代码一样。

@ServicepublicclassOrderService{@AutowiredprivateStockFeignClientstockFeignClient;// 注入动态代理对象publicvoidcreateOrder(LongstockId){// 1. 远程调用查询库存StockDTOstock=stockFeignClient.getById(stockId);System.out.println("当前库存:"+stock.getCount());// 2. 远程调用扣减库存stockFeignClient.deduct(1);}}

3. 生产环境必配:日志与超时

默认情况下,OpenFeign 是“哑巴”(不打印日志)且“急性子”(超时时间短),这在开发和生产中都不好用。

3.1 开启详细日志

Feign 的日志级别分为:NONE(默认),BASIC,HEADERS,FULL。开发环境建议开FULL

importfeign.Logger;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassFeignConfig{@BeanpublicLogger.LevelfeignLoggerLevel(){returnLogger.Level.FULL;// 打印 请求头、请求体、响应头、响应体}}

注意:还需要在application.yml中将该 Feign 接口包路径的日志级别设为 DEBUG,否则 Logback 不会输出。

logging:level:com.example.order.feign:DEBUG
3.2 配置超时时间
spring:cloud:openfeign:client:config:default:# 对所有服务生效,也可以替换为具体的服务名 "service-stock"connect-timeout:5000# 连接超时 (毫秒)read-timeout:5000# 读取/处理超时 (毫秒)logger-level:full# 也可以在这里配日志级别

2.OpenFeign 拦截器 (RequestInterceptor)

1. 原理

OpenFeign 允许我们定义一个或多个拦截器 (RequestInterceptor)。在 Feign 生成 HTTP 请求模板 (RequestTemplate) 之后、真正发送请求之前,这些拦截器会被执行。

核心作用Token 中继

  • 场景:用户访问 Service-A (带了 Token),Service-A 调用 Service-B。如果不做处理,Service-B 会报“未登录”,因为 Token 在 A 这里断掉了。拦截器可以把 A 收到的 Token 塞到去往 B 的请求头里。
2. Java 代码实战

步骤一:编写拦截器类

packagecom.example.order.config;importfeign.RequestInterceptor;importfeign.RequestTemplate;importjakarta.servlet.http.HttpServletRequest;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.context.request.RequestContextHolder;importorg.springframework.web.context.request.ServletRequestAttributes;@ConfigurationpublicclassFeignTokenInterceptorimplementsRequestInterceptor{@Overridepublicvoidapply(RequestTemplatetemplate){// 1. 获取当前请求的上下文(即用户发给 Order 服务的请求)ServletRequestAttributesattributes=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();if(attributes!=null){HttpServletRequestrequest=attributes.getRequest();// 2. 获取原始请求中的 TokenStringtoken=request.getHeader("Authorization");// 3. 将 Token 传递给下游服务(Stock 服务)if(token!=null){template.header("Authorization",token);}}// 也可以加一些自定义的内部 Headertemplate.header("X-From-Service","service-order");}}

步骤二:生效配置
只要加上@Configuration,这个拦截器就是全局生效的,所有 Feign 接口都会自动带上 Token。


3.Fallback 兜底机制 (结合 Sentinel)

在 Spring Cloud Alibaba 中,Feign 的熔断降级官方推荐使用Sentinel

1. 原理

OpenFeign 会利用动态代理,在发送请求时包裹一层 Sentinel 的资源保护逻辑。

  • 正常情况:执行远程调用。
  • 异常情况(网络超时、对方报错、对方宕机):捕获异常,不再抛给前端,而是执行配置好的fallback逻辑,返回默认值。
2. 准备工作

引入 Sentinel 依赖 (pom.xml)

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>

开启 Sentinel 对 Feign 的支持 (application.yml)
这是最容易忘的一步!默认是关闭的。

spring:cloud:openfeign:client:config:default:connect-timeout:2000read-timeout:2000sentinel:enabled:true# 【关键】开启 Sentinel 对 Feign 的支持
3. Java 代码实战 (推荐使用 FallbackFactory)

Feign 提供了两种方式:fallback(简单类) 和fallbackFactory(工厂类)。
**强烈推荐使用fallbackFactory**,因为它可以拿到具体的异常信息(是超时了?还是 404?还是 500?),方便记录日志。

步骤一:定义 Feign 接口

@FeignClient(name="service-stock",fallbackFactory=StockFeignClientFallbackFactory.class)publicinterfaceStockFeignClient{@PostMapping("/deduct")Stringdeduct(@RequestParam("count")Integercount);}

步骤二:编写 FallbackFactory 实现类

这个类必须注册为 Spring Bean (@Component)。

packagecom.example.order.feign.fallback;importcom.example.order.feign.StockFeignClient;importorg.springframework.cloud.openfeign.FallbackFactory;importorg.springframework.stereotype.Component;importlombok.extern.slf4j.Slf4j;@Slf4j@ComponentpublicclassStockFeignClientFallbackFactoryimplementsFallbackFactory<StockFeignClient>{@OverridepublicStockFeignClientcreate(Throwablecause){// 这里可以拿到具体的异常 'cause'// 返回一个实现了原接口的匿名内部类returnnewStockFeignClient(){@OverridepublicStringdeduct(Integercount){// 1. 记录降级日志,方便运维排查log.error("调用库存服务失败,触发兜底降级。原因:{}",cause.getMessage());// 2. 返回兜底数据// 比如:返回一个特定的 JSON 结构告诉前端"系统繁忙,请稍后"// 或者:如果是查询操作,可以返回缓存中的旧数据return"fallback-value: 库存扣减失败,服务忙";}};}}

总结与最佳实践

功能核心类/接口作用关键配置
拦截器RequestInterceptor传递 Token、TraceID@Configuration全局注入
兜底(简单)fallback = X.class仅返回默认值,不知异常原因feign.sentinel.enabled: true
兜底(推荐)fallbackFactory = X.class返回默认值 +获取异常堆栈feign.sentinel.enabled: true

开发建议:

  1. 必须要有兜底:永远不要相信网络和下游服务是 100% 稳定的。没有兜底的微服务就是裸奔。
  2. 兜底逻辑要简单:Fallback 方法里的逻辑不能太复杂(例如不要再去调数据库或另一个远程服务),否则兜底逻辑自己也挂了就尴尬了。通常只做日志记录 + 返回静态默认值。
http://www.cnnetsun.cn/news/619141.html

相关文章:

  • Hunyuan模型性能监控:Prometheus+Grafana集成教程
  • 终极指南:DS4Windows让PlayStation手柄在PC上完美运行
  • 终极完整指南:解锁老旧iOS设备新生命的替代工具链
  • 税务稽查:约谈过程语音文档化处理规范
  • SpringBoot+Vue 创新创业教育中心项目申报管理系统管理平台源码【适合毕设/课设/学习】Java+MySQL
  • DeepSeek-R1实战案例:自动化办公脚本生成部署流程
  • 前后端分离学生宿舍信息系统系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程
  • 2:调用大模型
  • Llama3-8B代码补全实战:VSCode插件开发对接指南
  • FSMN-VAD语音检测实测:精准识别语音片段,新手零配置上手
  • 亲测UI-TARS-desktop:用自然语言操控电脑的真实体验
  • SAM3进阶:模型蒸馏实现轻量化部署
  • 无需代码!基于CV-UNet镜像的中文WebUI实现快速图片去背
  • Hunyuan模型部署缺少依赖?requirements.txt避坑教程
  • 从图像到结构化数据|PaddleOCR-VL-WEB助力工业文档智能识别
  • Speech Seaco Paraformer科研助手:学术访谈语音资料结构化处理
  • Qwen3-0.6B API限流问题?高可用部署架构设计
  • 从Demo到上线:Paraformer-large生产级服务封装完整流程
  • Qwen2.5-7B-Instruct旅游咨询:行程规划生成系统
  • 仓储管理:货架标签图像方向校正
  • 计算机毕业设计springboot酒店管理系统 基于Spring Boot的酒店信息管理系统设计与实现 Spring Boot框架下的酒店综合管理系统开发
  • PKC(Public Key Cryptography)公钥密码学:把概念讲清楚、把算法讲明白、把场景讲落地
  • 京东AI影视创作大赛开启:最高10万元奖金,千万流量扶持
  • 后量子密码算法集成:微算法科技(NASDAQ: MLGO)构建区块链安全防护的量子盾牌
  • 5个必试SAM3应用场景:开箱即用镜像,10块钱全体验
  • Qwen2.5-7B企业级应用:低成本验证AI可行性
  • 腾讯混元模型妙用:HY-MT1.5云端做多语言SEO
  • 一键解析复杂PDF结构|深度体验科哥版PDF-Extract-Kit模型镜像
  • 告别环境冲突:ms-swift预置镜像,Python版本自动匹配
  • 提示词怎么写?麦橘超然电商应用中的工程实践