Spring Cloud:分布式系统的“粘合剂”(七)
专栏Spring Cloud个人主页手握风云目录一、RestTemplate 的问题二、OpenFeign 介绍三、OpenFeign 快速上手3.1. 引入依赖3.2. 开启功能3.3. 编写 Feign 客户端接口3.4. 调用远程接口四、OpenFeign 参数传递4.1. 单个普通参数Query 参数4.2. 多个普通参数4.3. 对象作为 Query 参数拼接4.4. 传递 JSON 请求体五、最佳实践5.1. Feign 继承方式5.2. Feign 抽取独立模块一、RestTemplate 的问题在前面的项目中我们可以使用RestTemplate完成微服务之间的HTTP远程调用。从示例代码能够看到调用方通过拼接目标服务的访问地址再借助 getForObject 方法发起 http 请求拿到远端返回的数据完成业务逻辑组装。public OrderInfo selectOrderById(Integer orderId) { OrderInfo orderInfo orderMapper.selectOrderById(orderId); String url http://product-service/product/ orderInfo.getProductId(); ProductInfo productInfo restTemplate.getForObject(url, ProductInfo.class); orderInfo.setProductInfo(productInfo); return orderInfo; }虽然 RestTemplate 已经对底层 HTTP 请求做了封装对比原生 HTTPClient使用上已经简化不少但是它依旧存在明显的缺陷。第一个问题是需要手动拼接 URL 地址。这种方式虽然灵活但是代码封装比较臃肿。当请求参数较多、URL 逻辑复杂的时候手动拼接字符串很容易出现书写错误引发调用异常。第二个问题是代码可读性差、编码风格不统一。远程调用的 http 请求逻辑直接写在业务方法内部URL字符串、返回值类型硬编码在代码中和普通本地方法调用写法差异很大阅读和维护起来不够直观。微服务主流的通信方式分为两种分别是 HTTP 通信与 RPC 通信。Spring Cloud 框架默认采用HTTP 实现微服务通信常用实现方案包含 RestTemplate 与 OpenFeign。RPC 全称远程过程调用核心思想是可以像调用本地方法一样调用远程服务使用者不需要关心底层网络通信的具体实现细节。RPC 并不限定底层协议可以使用 HTTP、TCP、UDP 等多种协议在TCP/IP四层模型中同时跨越传输层与应用层。业界常见的RPC框架有 Dubbo、Thrift、gRPC。二、OpenFeign 介绍OpenFeign 是一款声明式的 Web Service 客户端它能够简化微服务之间的远程调用。使用OpenFeign 发起调用的体验类似于 Controller 调用 Service开发者只需要定义接口并在接口上添加对应的注解就可以完成远程调用的全部配置。OpenFeign的前身是Netflix公司开源的Feign组件。2013年6月Netflix发布了Feign的第一个版本1.0.02016年7月Netflix发布Feign最后一个版本8.18.0之后Netflix将Feign捐赠给开源社区。同年7月OpenFeign发布首个版本9.0.0此后一直由社区持续维护更新。简单来说Netflix Feign就是OpenFeign的前身OpenFeign是在原有Feign基础之上升级而来功能更强大、使用也更加灵活。现在网络各类技术文章以及企业项目中使用的Feign基本都是OpenFeign。Spring Cloud Feign 是 Spring 框架对 Feign 做的一层封装目的是把 Feign 集成进 Spring Cloud完整生态。因为Feign项目更名Spring Cloud也提供了两套不同的starter依赖。旧版本为spring‑cloud‑starter‑feign新版本为 spring‑cloud‑starter‑openfeign。由于原始的Netflix Feign已经停止维护我们实际开发项目中要选用 spring‑cloud‑starter‑openfeign 这个依赖。如果需要查阅官方资料可以参考 OpenFeign 的GitHub文档以及 Spring Cloud OpenFeign的官方文档。OpenFeign 官方文档https://github.com/openfeign/feignSpring Cloud Feign 文档Spring Cloud OpenFeign三、OpenFeign 快速上手3.1. 引入依赖导入 spring‑cloud‑starter‑openfeigndependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-openfeign/artifactId /dependency3.2. 开启功能启动类增加注解 EnableFeignClients 开启 Feign。package com.yang.order; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; EnableFeignClients SpringBootApplication public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } }3.3. 编写 Feign 客户端接口FeignClient 注解修饰接口value/name 指定目标微服务名称用于 Nacos 服务发现底层自动负载均衡path 统一设置请求路径前缀接口方法直接使用 SpringMVC 注解定义请求路径、参数package com.yang.order.api; import com.yang.order.model.ProductInfo; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; FeignClient(value product-service, path /product) public interface ProductApi { RequestMapping(/{productId}) ProductInfo getProductInfo(PathVariable(productId) Integer productId); }3.4. 调用远程接口直接 Autowired 注入 Feign 接口像调用本地方法一样调用接口方法完成远程 http 调用。package com.yang.order.service; import com.yang.order.api.ProductApi; import com.yang.order.mapper.OrderMapper; import com.yang.order.model.OrderInfo; import com.yang.order.model.ProductInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; Service public class OrderService { Autowired private OrderMapper orderMapper; Autowired private RestTemplate restTemplate; Autowired private ProductApi productApi; public OrderInfo selectOrderById(Integer orderId) { OrderInfo orderInfo orderMapper.selectOrderById(orderId); /*String url http://product-service/product/ orderInfo.getProductId(); ProductInfo productInfo restTemplate.getForObject(url, ProductInfo.class);*/ ProductInfo productInfo productApi.getProductInfo(orderInfo.getProductId()); orderInfo.setProductInfo(productInfo); return orderInfo; } }四、OpenFeign 参数传递4.1. 单个普通参数Query 参数package com.yang.product.controller; import com.yang.product.model.ProductInfo; import com.yang.product.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/product) public class ProductController { RequestMapping(/p1) public String p1(Integer id) { return product-service 接收到参数, id: id; } }package com.yang.order.api; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; FeignClient(value product-service, path /product) public interface ProductApi { RequestMapping(/p1) public String p1(RequestParam(id) Integer id); }package com.yang.order.controller; import com.yang.order.api.ProductApi; import com.yang.order.model.ProductInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/feign) public class FeignController { Autowired private ProductApi productApi; RequestMapping(/o1) public String o1(Integer id) { return productApi.p1(id); } }4.2. 多个普通参数RequestMapping(/p2) public String p2(Integer id, String name) { return product-service 接收到参数, id: id , name: name; }RequestMapping(/p2) public String p2(RequestParam(id) Integer id, RequestParam(name) String name);RequestMapping(/o2) public String o2(Integer id, String name) { return productApi.p2(id, name); }4.3. 对象作为 Query 参数拼接RequestMapping(/p3) public String p3(ProductInfo productInfo) { return product-service 接收到参数: productInfo productInfo.toString(); }RequestMapping(/p3) public String p3(SpringQueryMap ProductInfo productInfo);RequestMapping(/o3) public String o3(ProductInfo productInfo) { productInfo.setId(45); productInfo.setProductName(T恤); return productApi.p3(productInfo); }4.4. 传递 JSON 请求体RequestMapping(/p4) public String p4(RequestBody ProductInfo productInfo) { return product-service 接收到参数: productInfo productInfo.toString(); }RequestMapping(/p4) public String p4(RequestBody ProductInfo productInfo);RequestMapping(/o4) public String o4(ProductInfo productInfo) { productInfo.setId(46); productInfo.setProductName(T恤); return productApi.p4(productInfo); }五、最佳实践5.1. Feign 继承方式Feign 支持继承的开发模式我们可以把公共的接口操作封装到单独的接口当中。具体思路为预先定义公共接口由服务提供方的 Controller 去实现这个接口而服务消费方编写 Feign 客户端接口时直接继承该公共接口即可。首先需要创建一个独立的 Module 模块这个模块用于存放公共接口打包生成 Jar 包之后可以同时给服务提供方和服务消费方共同依赖使用。创建模块完成后在 pom 文件引入 web 以及 openfeign 相关依赖接着把接口方法、实体模型复制到这个公共模块编写公共接口在接口上完整定义好所有请求相关的 SpringMVC 注解。package com.yang.common.api; import com.yang.common.model.ProductInfo; import org.springframework.cloud.openfeign.SpringQueryMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; public interface ProductInterface { RequestMapping(/{productId}) ProductInfo getProductById(PathVariable(productId) Integer productId); RequestMapping(/p1) String p1(RequestParam(id) Integer id); RequestMapping(/p2) String p2(RequestParam(id) Integer id, RequestParam(name) String name); RequestMapping(/p3) String p3(SpringQueryMap ProductInfo productInfo); RequestMapping(/p4) String p4(RequestBody ProductInfo productInfo); }package com.yang.common.model; import lombok.Data; import java.util.Date; Data public class ProductInfo { private Integer id; private String productName; private Integer productPrice; private Integer state; private Date createTime; private Date updateTime; }完成代码编写之后通过 Maven 执行打包、install 命令将生成的 Jar 包安装到本地 Maven 仓库确认 Jar 包构建成功。对于服务提供方只需要让 Controller 类实现刚刚定义好的公共接口然后重写接口中的业务方法完成业务逻辑实现即可不需要再重复书写 RequestMapping 等请求注解。对于服务消费方创建 Feign 客户端接口添加FeignClient注解直接继承来自公共模块的接口不需要再重复定义接口方法。完成后启动项目发起远程调用进行功能测试。5.2. Feign 抽取独立模块虽然官方推荐继承的实现方式但是在真实企业开发当中更常采用将 Feign 接口抽取为独立模块的方案。该方案和继承模式操作上有相似之处但设计理念不一样。该方案的处理逻辑是将完整的Feign Client客户端以及业务涉及的实体类全部抽取到独立Module模块将模块打包为Jar包服务消费方直接引入这个Jar包就可以获得Feign调用能力。在企业项目中这个公共Jar包一般由服务提供方负责维护。首先新建独立 Module 模块在模块中引入 openfeign 依赖把 Feign 客户端接口、实体Model类全部复制到此模块中。通过 Maven 执行 install将该模块打包安装到本地仓库。服务消费方做如下修改删除项目内部原本手写的 Feign 接口与实体类在 pom 当中引入刚刚打包好的公共 Jar 依赖修改代码当中实体类、接口的导入路径指向Jar包内的类。由于 Feign 接口存放在外部 Jar启动类上的 EnableFeignClients 注解需要指定扫描范围有两种配置方式第一种通过 basePackages 指定扫描的包路径第二种通过 clients 属性直接指定要加载的 Feign 客户端 Class 对象。配置完成后启动项目进行远程调用测试。package com.yang.order; import com.yang.common.api.ProductApi; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; EnableFeignClients(clients {ProductApi.class}) SpringBootApplication public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } }

相关新闻

Python数学建模实战:NetworkX图论与最短路径算法应用

Python数学建模实战:NetworkX图论与最短路径算法应用

1. 项目概述:从“解题”到“建模”的思维跃迁“数学建模Python实现基础编程练习4”这个标题,听起来像是一本教材或一个课程系列中的标准作业。但如果你真这么想,可能就错过了它背后最核心的价值。作为一名参与过多次数学建模竞赛并指导过不少…

2026/10/27 8:56:13 阅读更多 →
vue 甘特图组件 vxe-gantt 紧前紧后依赖关系连接线配置详解

vue 甘特图组件 vxe-gantt 紧前紧后依赖关系连接线配置详解

在项目管理、生产排程、研发计划等场景中,甘特图是展示任务时间线与依赖关系的核心工具。任务依赖关系(即“紧前紧后关系”)决定了任务执行的先后顺序,直接影响项目进度的计算与关键路径的识别。 vxe-gantt 作为 Vxe 生态中的专业…

2026/10/26 8:57:27 阅读更多 →
从10万并发崩溃到百万级稳定:星逐赛事体育直播源码的高可用架构演进之路

从10万并发崩溃到百万级稳定:星逐赛事体育直播源码的高可用架构演进之路

这套架构已在星逐赛事源码中完整实现。代码开源无加密,支持二次开发。演示站已搭建,想了解技术细节或查看效果,欢迎私信交流。 去年五大联赛期间,巴萨vs皇马国家德比,我们的平台在巅峰时刻直接崩溃了。 10万用户同时涌…

2026/10/16 15:33:51 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/31 0:19:11 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/31 10:20:19 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/31 10:20:23 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/31 0:59:28 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/31 10:30:19 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/31 9:29:43 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/30 17:32:24 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/31 11:00:40 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/31 0:09:01 阅读更多 →