【SpringCloud】使用OpenFeign进行微服务化改造
目录
- 一、需求与背景
- 二、OpenFeign 远程调用技术原理
- 三、项目代码演示
- 3.1 引入依赖
- 3.2 实现@OpenFeign注解修饰接口
- 3.3 指定 OpenFeign 远程调用接口的扫描路径
- 四、OpenFeign 在日志中打印Request和Response
- 五、OpenFeign 客户端超时配置
- 六、使用 OpenFeign 实现服务降级
- 6.1 实现降级
- 6.1.1 引入依赖
- 6.1.2 降级方式一
- 6.1.2 降级方式二
- 6.2 开启降级配置
一、需求与背景
- 在分布式系统的场景下,大多数服务的拆分要进行微服务化,各微服务的内部不可能直接依赖其它微服务的实现,而是将该微服务内的POJO 类提取到一个公共模块,供其它的微服务进行依赖。
- 为了让代码的职责更加明确,实现更加清晰,就需要将业务代码与框架使用的模版代码分离,让开发人员将精力集中到业务功能的实现上。
二、OpenFeign 远程调用技术原理
- OpenFeign 是 Netflix 开源的一个项目,可以将远程的接口调用转换成本地调用的形式,简化了开发,并且做到了业务功能代码与框架模版代码分离的效果。
- OpenFeign 的使用核心是基于
@FeignClient
、@EnableFeignClients
这2个注解。@EnableFeignClients
注解加在项目的启动类上,当项目在启动时,会扫描注解中指定的目录,会为所有使用了@FeignClient
注解的接口创建一个动态代理对象,这些被创建的动态代理对象从属于@FeignClient
注解所修饰的接口的实例,并把这些动态代理对象加载到 Spring 的 Bean 容器内,随后会被注入到需要进行远程调用的本地服务对象内。
三、项目代码演示
接下来使用一个积分项目进行演示。这个项目分为3个微服务:商品(goods)、用户(customer)、计算(caculation)。用户通过购买商品获取积分;不同的商品可能参加了不同的活动,有的商品不赠送积分;不同的用户等级可能通过购物获取的积分不同。
3.1 引入依赖
要使用 openFeign
组件,首先我们需要先引入相应的依赖。注意,使用openFeign
还需要引入loadBalancer
的依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
由于在父项目中已经引入了 spring-cloud-dependencies
的依赖,上述2个组件的版本号可通过版本仲裁确定,无需指定。
3.2 实现@OpenFeign注解修饰接口
实现OpenFeign组件的远程调用,首先需要实现@FeignClient
注解修饰的接口,该接口会将本地调用转化成远程的接口调用。
@FeignClient(value = "coin-goods-svc", path = "/goods")
public interface GoodsService {// 获取指定商品@GetMapping("/getGoods")GoodsInfo getGoods(@RequestParam("id") Long id);// 获取整个购物车内的商品@GetMapping("/getBatch")Map<Long, GoodsCart> getGoodsCart(@RequestParam("ids") Collection<Long> ids);
}
原来我们是直接通过 webclient 直接发起的远程接口调用,内容如下:
webClientBuilder.build().get().uri("http://coin-goods-svc/goods/getGoods?id=" + id).retrieve().bodyToMono(GoodsInfo.class).block();
现在我们直接注入 GoodsService
并调取对应方法:
@Autowired
private GoodsService goodsService;public Integer getGoodsCoin(Long id) {// 忽略无关逻辑// 获取指定商品GoodsInfo goods = goodsService.getGoods(id);
}
现在我们不必再业务代码里面指定调用接口的URI 和 Method 了,做到了代码的职责分离。
3.3 指定 OpenFeign 远程调用接口的扫描路径
接下来,我们需要在微服务的启动类上加上 @EnableFeignClients
注解,这样服务启动时的,才会扫描指定目录下使用了 @FeignClient
注解的接口,并为其生成对应的动态代理实例。
// 省略其它注解
@EnableFeignClients(basePackages = {"com.fyup"})
public class CustomerApplication{// 忽略具体实现
}
我们也可以不指定具体的扫描路径,而是直接指定要进行代理的接口,不过这种方式在 OpenFeign
远程调用接口较多时会很麻烦,不具备扩展性,不符合开闭原则。
// 通过指定具体的远程调用接口
// 省略其它注解
@EnableFeignClients(clients = {GoodsService.class})
public class CustomerApplication{// 忽略具体实现
}
四、OpenFeign 在日志中打印Request和Response
OpenFeign 还提供了在日志中打印远程调用细节的功能,只需要开启相应配置,并向 Spring Bean 容器内注册对应的 Bean 即可。可打印的日志分为4个级别,这里贴一下源码的截图:
如上所示,如果我们选择 Level.FULL
级别,会打印完整的 Request 和 Response 的 Header、Body。
因为 OpenFeign 组件内的日志都是以 Debug
级别输出的,所以我们需要现将对应的远程调用接口的日志输出级别打开。
logging:level:com.fyup.coin.customer.feign.GoodsService: debug
因为要打印完整的 URL、Method、以及Request 和 Response 的 Header、Body 等信息,所以还需要在配置类中注入 Level.FULL
的 Bean。实现如下:
@Bean
Logger.Level feignLogger() {return Logger.Level.FULL;
}
五、OpenFeign 客户端超时配置
接口超时不响应会悬挂消费者请求,大量的请求超时未响应会给系统造成很大压力,在调用链路过长的情况下可能会在系统内部产生雪崩反应。
我们可以在Feign客户端的application.yml
文件中的 feign.client.config
配置项配置Feign 客户端远程调用的超时时间。feign.client.config.default
配置项配置全局的超时时间,通过 feign.client.config.${serviceName}
配置访问某个特定微服务的超时时间。 示例配置如下:
# 其它忽略
feign:client:config:# 全局超时配置default:connectTimeout: 1000readTimeout: 3000# 针对coin-goods-svc服务的超时配置coin-goods-svc:connectTimeout: 1000readTimeout: 2000
其中,connectTimeout
表示的是服务消费者与服务提供者建立远程连接的超时时间;
readTimeout
是指从发出请求开始,到服务端响应请求之前为客户端设置的请求超时时间。
六、使用 OpenFeign 实现服务降级
我们也可以使用 OpenFeign
组件实现服务降级,用法就是使用 @FeignClient
注解修饰远程调用接口时,使用 @FiegnClient
注解的 fallback
属性或者 fallbackFactory
属性指定降级方法的降级类即可。
6.1 实现降级
6.1.1 引入依赖
因为OpenFeign
实现服务降级依赖于 hystrix
,因此我们需要先引入hystrix
依赖如下:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId><version>2.2.9.RELEASE</version><exclusions><exclusion><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-netflix-ribbon</artifactId></exclusion></exclusions>
</dependency>
6.1.2 降级方式一
下面实现了一个降级类示例,该降级类是通过 @FiegnClient
注解的 fallback
属性来指定的:
@Slf4j
@Component
public class GoodsServiceDowngrade implements GoodsService {// 获取指定商品@Overridepublic GoodsInfo getGoods(Long id) {// 对应的远程调用方法执行失败后会调用该方法,根据业务情况自行设计实现细节,此处仅打印日志log.info("fallback method in getGoods.");return null;}// 获取整个购物车内的商品@Overridepublic Map<Long, GoodsCart> getGoodsCart(Collection<Long> ids) {// 对应的远程调用方法执行失败后会调用该方法,根据业务情况自行设计实现细节,此处仅打印日志log.info("fallback method in getGoodsCart.");return null;}
}
接下来在远程调用接口内指定降级类:
@FeignClient(value = "coin-goods-svc", path = "/goods", fallback=GoodsServiceDowngrade.class)
public interface GoodsService {// 获取指定商品@GetMapping("/getGoods")GoodsInfo getGoods(@RequestParam("id") Long id);// 获取整个购物车内的商品@GetMapping("/getBatch")Map<Long, GoodsCart> getGoodsCart(@RequestParam("ids") Collection<Long> ids);
}
6.1.2 降级方式二
下面实现的降级类,是通过 @FiegnClient
注解的 fallbackFactory
属性来指定的,与上面不同的是,使用降级工厂处理降级可以获取到远程调用方法失败的原因。
@Slf4j
@Component
public class GoodsServiceDowngradeFactory implements FallbackFactory<GoodsService> {@Overridepublic GoodsService create(Throwable cause) {return new GoodsService() {@Overridepublic GoodsInfo getGoods(Long id) {// 根据业务情况自行设计实现细节,此处仅打印日志log.info("fallback method in getGoods.", cause);return null;}@Overridepublic Map<Long, GoodsCart> getGoodsCart(Collection<Long> ids) {log.info("fallback method in getGoodsCart.", cause);return null;}};}
}
下面我们在@FeignClient
注解修饰的远程调用接口内使用我们实现的降级工厂:
@FeignClient(value = "coin-goods-svc", path = "/goods", fallbackFactory=GoodsServiceDowngradeFactory.class)
public interface GoodsService {// 获取指定商品@GetMapping("/getGoods")GoodsInfo getGoods(@RequestParam("id") Long id);// 获取整个购物车内的商品@GetMapping("/getBatch")Map<Long, GoodsCart> getGoodsCart(@RequestParam("ids") Collection<Long> ids);
}
注意我们在使用的时候,降级类和降级工厂同时只能选择其中一种。
6.2 开启降级配置
最后一步,开启降级的配置开关feign.circuitbreaker.enabled: true
,使代码生效。即在 application.yml
文件中,原来的配置中加上:
# 其它忽略
feign:client:config:# 全局超时配置default:connectTimeout: 1000readTimeout: 3000# 针对coin-goods-svc服务的超时配置coin-goods-svc:connectTimeout: 1000readTimeout: 2000circuitbreaker:enabled: true
相关文章:

【SpringCloud】使用OpenFeign进行微服务化改造
目录 一、需求与背景二、OpenFeign 远程调用技术原理三、项目代码演示3.1 引入依赖3.2 实现OpenFeign注解修饰接口3.3 指定 OpenFeign 远程调用接口的扫描路径 四、OpenFeign 在日志中打印Request和Response五、OpenFeign 客户端超时配置六、使用 OpenFeign 实现服务降级6.1 实…...

DRV8313和L298N都是电机驱动,一个是驱动三相FOC无刷直流电机的,一个是驱动有刷电机,使stm32控制无刷电机简单入门知识
DRV8313和L298N都是电机驱动器,但它们之间存在一些关键的区别: DRV83131: 由德州仪器(TI)制造。 具有集成的场效应晶体管(FET)。 最大电压为65V。 峰值电流为3A。 适用于三相电机驱动。 L298N…...

React16源码: React中event事件系统初始化源码实现
event 事件系统初始化 1 )概述 react事件系统比较的复杂,它是基于dom的事件系统在dom事件系统上面进行了一个深度的封装它里面的很多实现逻辑都是自由的一套在初始化 react-dom 的源码的时候,会为react的事件系统注入 reactdom 相关的一些插…...

Qt6入门教程 15:QRadioButton
目录 一.简介 二.常用接口 三.实战演练 1.径向渐变 2.QSS贴图 3.开关效果 4.非互斥 一.简介 QRadioButton控件提供了一个带有文本标签的单选按钮。 QRadioButton是一个可以切换选中(checked)或未选中(unchecked)状态的选项…...

Json序列化和反序列化 笔记
跟着施磊老师学C 下载:GitHub - nlohmann/json: JSON for Modern C 在single_include/nlohmann里头有一个json.hpp,把它放到我们的项目中就可以了 #include "json.hpp" using json nlohmann::json;#include <iostream> #include <…...

新媒体与传媒行业数据分析实践:从网络爬虫到文本挖掘的综合应用,以“中国文化“为主题
大家好,我是八块腹肌的小胖, 下面将围绕微博“中国文化”以数据分析、数据处理、建模及可视化等操作 目录 1、数据获取 2、数据处理 3、词频统计及词云展示 4、文本聚类分析 5、文本情感倾向性分析 6、情感倾向演化分析 7、总结 1、数据获取 本…...

Visual Studio使用Git忽略不想上传到远程仓库的文件
前言 作为一个.NET开发者而言,有着宇宙最强IDE:Visual Studio加持,让我们的开发效率得到了更好的提升。我们不需要担心环境变量的配置和其他代码管理工具,因为Visual Studio有着众多的拓展工具。废话不多说,直接进入正…...

Nginx简单阐述及安装配置
目录 一.什么是Nginx 二.Nginx优缺点 1.优点 2.缺点 三.正向代理与反向代理 1.正向代理 2.反向代理 四.安装配置 1.添加Nginx官方yum源 2.使用yum安装Nginx 3.配置防火墙 4.启动后效果 一.什么是Nginx Nginx(“engine x”)是一个高性能的HTTP…...

【遥感入门系列】遥感分类技术之遥感解译
遥感的最终成果之一就是从遥感图像上获取信息,遥感分类是获取信息的重要手段。同时遥感图像分类也是目前遥感技术中的热点研究方向,每年都有新的分类方法推出。 本小节主要内容: 遥感分类基本概念常见遥感分类方法 1 遥感分类概述 遥感图…...

解决:IDEA无法下载源码,Cannot download sources, sources not found for: xxxx
原因 Maven版本太高,遇到http协议的镜像网站会阻塞,要改为使用https协议的镜像网站 解决方案 1.打开设置 2. 拿到settings.xml路径 3. 将步骤2里箭头2的User settings file:settings.xml打开,作以下修改 保存即可。如果还不行…...

什么是IDE,新手改如何选择IDE?
IDE 是 Integrated Development Environment(集成开发环境)的缩写,它是一种软件应用程序,为程序员提供了一站式的开发环境,整合了多种工具和服务,以便高效地创建、修改、编译、调试和运行软件程序。IDE 集成…...

springBoot+Vue汽车销售源码
源码描述: 汽车销售管理系统源码基于spring boot以及Vue开发。 针对汽车销售提供客户信息、车辆信息、订单信息、销售人员管理、 财务报表等功能,提供经理和销售两种角色进行管理。 技术架构: idea(推荐)、jdk1.8、mysql5.X(不能为8驱动不匹配)、ma…...

FPS游戏框架漫谈第五天
今天想了想整理下AnimatorManager 他的职责是负责动画的播放,那么在介绍该对象具备的对外接口,必须先介绍下拥有动画的对象他是怎么管理动画数据的,打个比方如果我们一个把武器需要播放开火动画,那么我们基于unity引擎可视化动画编…...

83.如何设计高可用系统
文章目录 一、简介二、导致系统不可用的常见原因三、高可用系统设计基本原则四、容错性设计五、弹性伸缩六、可观测七、安全防护设计八、自动化 一、简介 什么是高可用 高可用是指系统在面对各种故障和异常情况时,仍能够提供稳定、可靠的服务。对于企业和用户而言&…...

Map和Set讲解
🎥 个人主页:Dikz12📕格言:那些在暗处执拗生长的花,终有一日会馥郁传香欢迎大家👍点赞✍评论⭐收藏 目录 集合框架 模型 Set 常见方法和说明 Set总结 Map说明 Map常见方法和说明 Map 中HashMap的 …...

PHP集成开发环境 PhpStorm 2023 for mac中文激活版
PhpStorm 2023 for Mac是一款功能强大的PHP集成开发环境(IDE),旨在帮助开发者更高效地编写、调试和测试PHP代码。该软件针对Mac用户设计,提供了丰富的功能和工具,以简化开发过程并提高开发效率。 软件下载:…...

数学建模 - 线性规划入门:Gurobi + python
在工程管理、经济管理、科学研究、军事作战训练及日常生产生活等众多领域中,人们常常会遇到各种优化问题。例如,在生产经营中,我们总是希望制定最优的生产计划,充分利用已有的人力、物力资源,获得最大的经济效益&#…...

SpringBoot security 安全认证(二)——登录拦截器
本节内容:实现登录拦截器,除了登录接口之外所有接口访问都要携带Token,并且对Token合法性进行验证,实现登录状态的保持。 核心内容: 1、要实现登录拦截器,从Request请求中获取token,从缓存中获…...

详解WebRTC rtc::Thread实现
rtc::Thread介绍 rtc::Thread类不仅仅实现了线程这个执行器(比如posix底层调用pthread相关接口创建线程,管理线程等),还包括消息队列(message_queue)的实现,rtc::Thread启动后就作为一个永不停止的event l…...

阿赵UE学习笔记——13、贴花
阿赵UE学习笔记目录 大家好,我是阿赵。 继续学习虚幻引擎的使用。这次介绍一种特殊的材质类型,贴花。 一、获取贴花资源 在没有分析贴花的原理之前,可以先去获得一些免费的贴花资源来使用,比如在Quixel上面就有专门的一个资源…...

简单说说mysql的日志
今天我们通过mysql日志了解mysqld的错误日志、慢查询日志、二进制日志,redolog, undolog等。揭示它们的作用和用途,让我们工作中更能驾驭mysql。 redo 日志 如果mysql事务提交后发生了宕机现象,那怎么保证数据的持久性与完整性?…...

如何在CentOS安装DataEase数据分析服务并实现远程访问管理界面
如何在CentOS安装DataEase数据分析服务并实现远程访问管理界面 前言1. 安装DataEase2. 本地访问测试3. 安装 cpolar内网穿透软件4. 配置DataEase公网访问地址5. 公网远程访问Data Ease6. 固定Data Ease公网地址 🌈你好呀!我是 是Yu欸 🌌 202…...

HTTP请求传递参数方式【2024-02-01】
1、HTTP请求传递参数分类 1.1、按照请求方式分类 GET方法:通过查询字符串(Query String,每个参数由参数名和参数值组成,使用等号 连接,不同参数之间使用 & 符号分隔)的方式或直接将参数放在URL中来传递参数POST…...

Error: Projects must list all files or use an ‘include‘ pattern.
博主介绍:✌全网粉丝5W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…...

移动应用开发的方式
移动应用开发的方式(三种) Native App: 本地应用程序(原生App) Web App:网页应用程序(移动web) Hybrid App:混合应用程序(混合App) hybrid应用场景 1、微信公众号&…...

C#学习笔记_类(Class)
类的定义 类的定义是以关键字 class 开始,后跟类的名称。类的主体,包含在一对花括号内。 语法格式如下: 访问标识符 class 类名 {//变量定义访问标识符 数据类型 变量名;访问标识符 数据类型 变量名;访问标识符 数据类型 变量名;......//方…...

壹[1],Xamarin开发环境配置
1,环境 VS2022 注: 1,本来计划使用AndroidStudio,但是也是一堆莫名的配置让人搞得很神伤,还是回归C#。 2,MAUI操作类似,但是很多错误解来解去,且调试起来很卡。 3,最…...

SAM:基于 prompt 的通用图像分割模型
Paper: Kirillov A, Mintun E, Ravi N, et al. Segment anything[J]. arXiv preprint arXiv:2304.02643, 2023. Introduction: https://segment-anything.com/ Code: https://github.com/facebookresearch/segment-anything SAM 是 Meta AI 开发的一款基于 prompt 的通用视觉大…...

2024美赛数学建模C题思路+模型+代码+论文
2024美赛A-F题思路代码模型论文:2.2开赛第一时间更新,获取见文末名片 美赛流程以及经验分享 今天主要和大家分享一下我之前参加美赛的经验,主要分两部分来讲。一部分是美赛流程,另一部分是美赛经验。 一 美赛流程 比赛前&#x…...

npm run serve和npm run dev的区别
1. 功能:通常,"npm run serve"用于启动开发服务器,提供实时的开发环境,支持自动重新加载和热模块替换。这样可以在开发过程中实时查看代码更改的效果。而"npm run dev"可以是一个自定义的指令,用于…...