SpringCloudAlibaba OpenFeign整合及详解

SpringCloudAlibaba OpenFeign

在前面,我们使用Nacos服务注册发现后,服务远程调用可以使用RestTemplate+Ribbon或者OpenFeign调用。实际开发中很少使用RestTemplate这种方式进行调用服务,每次调用需要填写地址,还要配置各种的参数,很麻烦。使用OpenFeign的方式就可以解决这种问题。

那么说起了OpenFeign,就需要提及一下Feign了,因为OpenFeign是Feign的增强版。Feign是一个轻量级Restful HTTP服务客户端,内置ribbon用作客户端负载均衡,使用Feign时只需要定义一个接口加上注解,符合面向接口的编程习惯,使远程调用服务更加容易。

OpenFeign是对Feign的进一步封装,使其支持Spring MVC的标准注解和HttpMessageConverters,如@RequestMapping等。

集成OpenFeign

在消费者客户端中集成OpenFeign

导入依赖

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

bootstrap.yml中增加OpenFeign对Sentinel的支持,增加feign.sentinel.enabled配置项

server:port: 9001
spring:application:name: consumer # 应用名cloud:nacos:discovery:server-addr: localhost:8848 # nacos服务地址sentinel:transport:port: 8719 # 启动http server,并且该服务与Sentinel仪表板进行交互,使sentinel可以控制应用,若端口占用则8719+1依次扫描dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:	# 增加对sentinel的支持sentinel:enabled: true

这里说一下如果不加feign.sentinel.enabled=true的配置,那么在@FeignClient中定的fallback属性定义的异常、限流等自定义的处理逻辑不会生效

在主启动类上加入@EnableFeignClients注解,标记为启用OpenFeign,具体如下:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class Consumer {public static void main(String[] args) {SpringApplication.run(Consumer.class, args);}
}

笔者这里再提一句,假如是分布式项目,将openfeign抽取为一个单独的服务模块时,可能出现我openfeign中的包名和其他模块不一致,可以自己声明FeignClient组件的basePackages设置一下FeignClient的扫描路径。示例如下:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.alibaba.provider.feigns")
public class Consumer {public static void main(String[] args) {SpringApplication.run(Consumer.class, args);}
}

增加一个FeignClient的客户端

/*** "provider" : 表示调用的生产者服务名* fallback:异常时进入的处理类*/
@FeignClient(value = "provider", fallback = OpenFeignTestServiceFallback.class)
public interface OpenFeignTestService {@RequestMapping(value = "/openFeignProviderTest", method = RequestMethod.GET)public String openFeignProviderTest();}

创建OpenFeignTestServiceFallback做fallback处理

@Component
public class OpenFeignTestServiceFallback implements OpenFeignTestService{@Overridepublic String openFeignProviderTest() {return "我是兜底方法";}
}

创建controller做个接口,方便调用

@RestController
public class OpenFeignTestController {@Resourceprivate OpenFeignTestService openFeignTestService;@RequestMapping("/openFeignTest")public String openFeignTest() {return openFeignTestService.openFeignProviderTest();}}

在服务生产者方,提供接口

@RestController
public class OpenFeignProviderTest {@RequestMapping("/openFeignProviderTest")public String openFeignProviderTest() {return "OpenFeignTestController#openFeignProviderTest" + RandomUtils.nextInt(0, 1000);}}

测试接口

使用curl或浏览器都行,调用服务消费者方的/openFeignTest接口测试

curl http://localhost:9001/openFeignTest
==>OpenFeignTestController#openFeignProviderTest748

代码优化一下:

在@FeignClient注解中,value属性填写的是服务提供者的服务名称,这么把值直接写死是不合适的,假如服务提供者名称变了,那么这里写的就需要修改,而且如果用的地方比较多的情况下,需要到处修改。如何解决呢?

  • 把服务名用一个单独的类,定义静态常量
  • 使用配置文件方式,使用表达式获取即可

定义静态常量类就不再演示,使用配置文件方式:

provider:name: provider

在FeignClient客户端使用表达式获取

@FeignClient(value = "${provider.name}", fallback = OpenFeignTestServiceFallback.class)

结合sentinel规则使用

不管是RestTemplate+Ribbon还是OpenFeign的远程调用,都是支持Sentinel的,到sentinel面板中配置资源流控规则

注意:sentinel是懒加载方式,需要先去调用一次接口,才能在控制台添加规则

在sentinel面板,新增openFeignProviderTest流控规则,阈值类型QPS,单机阈值1

在这里插入图片描述

欧克,我们对服务端的,/openFeignProviderTest做了限流,那么试试多次连续访问客户端接口试试。

在这里插入图片描述

可以看到,有请求会进入到fallback降级中。

那么对于异常该怎么处理呢?

修改服务端接口代码,设置一个异常,进行测试接口

在这里插入图片描述

欧克,发现,服务端如果是出现了异常,仍然会进入客户端的fallback处理中,是不是非常奈斯。

那么同样的,假如服务器进入宕机状态,会如何?关掉服务端试试。

在这里插入图片描述

行的,一样可以进入到fallback处理中。

实现负载均衡

OpenFeign也具有负载均衡的功能,多个服务端时,采用对应的算法寻找一个服务端进行请求。

下面,服务端将输出当前项目的端口号,并且再新建一个服务端的项目

@RestController
public class OpenFeignProviderTest {@Value("${server.port}")private Integer port;@RequestMapping("/openFeignProviderTest")public String openFeignProviderTest() {return "OpenFeignTestController#openFeignProviderTest" + port;}}

再新建一个项目,端口为8003即可。

server:port: 8002
...多余部分省略server:port: 8003
...多余部分省略

项目启动,nacos中可以发现,服务端两个实例

在这里插入图片描述

多次调用客户端接口,看结果

在这里插入图片描述

依次轮询方式请求服务。

OpenFeign的超时配置

2020版本以前的OpenFeign的默认等待接口返回数据的时间是1s,超过1秒就报错,如果有fallback,那么执行fallback的处理。

2020版本后,源码如下:

public Options() {//10L: connectTimeout//60L: readTimeoutthis(10L, TimeUnit.SECONDS, 60L, TimeUnit.SECONDS, true);
}

connectTimeout是10s,readTimeout是60s

普通接口是没有问题的,但是如果是一些耗时业务,执行过程中一定是大于1s的,不太合理。

那么OpenFeign提供了超时的配置。消费者bootstrap.yml文件中增加超时配置:

  • feign.client.config.default.connectTimeout:建立连接的超时时间
  • feign.client.config.default.readTimeout:建立连接后从服务器读取资源所用时间的超时时间配置
server:port: 9001
spring:application:name: consumer # 应用名cloud:nacos:discovery:server-addr: localhost:8848 # nacos服务地址sentinel:transport:port: 8719 # 启动http server,并且该服务与Sentinel仪表板进行交互,使sentinel可以控制应用,若端口占用则8719+1依次扫描dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:sentinel:enabled: trueclient:config:default:connectTimeout: 2000 # 建立连接超时时间readTimeout: 2000   # 读取资源超时时间
@RequestMapping("/openFeignProviderTest")
public String openFeignProviderTest() throws InterruptedException {Thread.sleep(5000);return "OpenFeignTestController#openFeignProviderTest" + port;
}

在这里插入图片描述

这里故意睡眠5s,超时时间是2s那么,一定是超时了,会进入fallback.

时间调长点试试

..
feign:sentinel:enabled: trueclient:config:default:connectTimeout: 7000 # 建立连接超时时间readTimeout: 7000   # 读取资源超时时间

在这里插入图片描述

没问题

OpenFeign的日志

为方便查找异常,一般在本地开发环境中,把OpenFeign远程调用接口的日志详情打印出来。

服务消费者bootstrap.yml文件新增日志级别的配置,新增配置项logging.level.声明接口的包名,完整配置如下:

server:port: 9001
spring:application:name: consumer # 应用名cloud:nacos:discovery:server-addr: localhost:8848 # nacos服务地址sentinel:transport:port: 8719 # 启动http server,并且该服务与Sentinel仪表板进行交互,使sentinel可以控制应用,若端口占用则8719+1依次扫描dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:sentinel:enabled: trueclient:config:default:connectTimeout: 5000 # 建立连接超时时间readTimeout: 5000   # 读取资源超时时间logging:level:com.alibaba.provider.feigns: debug # 打印自己项目中com.alibaba.provider.feigns包的日志,级别是debug级别

然后在java中创建一个配置类

@Configuration
public class OpenFeignLoggerConfiguration {@Beanpublic Logger.Level openFeignLoggerLevel() {return Logger.Level.FULL;   // FULL日志级别}}

OpenFeign日志有以下几个级别

  • NONE:无记录,默认的
  • BASIC:只记录请求方法和url及响应状态代码和执行时间
  • HEADERS:只记录基本信息及请求和响应头
  • FULL:记录请求和响应的头文件,正文和元数据,信息最全

配置后日之后,如下:

在这里插入图片描述

信息非常完整,方便排错。

请求和响应压缩

OpenFeign支持通过简单配置实现请求和响应进行gzip压缩,提高数据传输的效率。

开启压缩可以有效节约网络资源,但是在压缩和解压过程中会增加CPU的压力,最好把最小请求长度参数调大一些。

bootstrap.yml文件中,增加参数配置(服务消费者端):

server:port: 9001
spring:application:name: consumer # 应用名cloud:nacos:discovery:server-addr: localhost:8848 # nacos服务地址sentinel:transport:port: 8719 # 启动http server,并且该服务与Sentinel仪表板进行交互,使sentinel可以控制应用,若端口占用则8719+1依次扫描dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:sentinel:enabled: trueclient:config:default:connectTimeout: 5000 # 建立连接超时时间readTimeout: 5000   # 读取资源超时时间compression:request:enabled: true # 请求压缩启用mime-types: text/xml, application/xml, application/json # 要压缩的类型min-request-size: 2048 # 最小请求长度 单位:字节response:enabled: true # 响应压缩启用logging:level:com.alibaba.provider.feigns: debug # 打印com.alibaba.provider.feigns包的日志,级别是debug级别

压缩后,可以看下日志情况:

在这里插入图片描述

OpenFeign的参数传递

简单参数传递

服务端接口

@PostMapping("/sampleParamsProviderTest")
public String sampleParamsProviderTest(@RequestParam("name") String name, @RequestParam("id") Integer id) {return "OpenFeignProviderTest# sampleParamsProviderTest#" + port + "id=" + id + ",name=" + name;
}

消费者OpenFeign

@FeignClient(value = "${provider.name}", fallback = OpenFeignTestServiceFallback.class)
public interface OpenFeignTestService {@PostMapping("/sampleParamsProviderTest")public String sampleParamsProviderTest(@RequestParam("name") String name, @RequestParam("id") Integer id);}

消费者fallback

@Component
public class OpenFeignTestServiceFallback implements OpenFeignTestService {@Overridepublic String sampleParamsProviderTest(String name, Integer id) {return "我是兜底方法" + name + id;}
}

消费者提供一个接口做测试

@GetMapping("/sampleParamsProviderTest")
public String sampleParamsProviderTest() {return openFeignTestService.sampleParamsProviderTest("gangge", 1);
}

在这里插入图片描述

@SpringQueryMap对象传递

那么先创建一个要传递的对象,服务提供者和消费者共用

public class Params {private Integer id;private String name;.../getter、setter方法
}

服务提供者,创建一个给消费者调用的接口

@GetMapping("/springQueryMapProviderTest")
public String springQueryMapProviderTest(Params params) {return "OpenFeignProviderTest# sampleParamsProviderTest#" + port + "id=" + params.getId() + ",name=" + params.getName();
}

消费者OpenFeign

@GetMapping("/springQueryMapProviderTest")
public String springQueryMapProviderTest(@SpringQueryMap Params params);

消费者fallback

@Override
public String springQueryMapProviderTest(Params params) {return "我是兜底方法" + params.getId() + params.getName();
}

消费者接口

@GetMapping("/springQueryMapTest")
public String springQueryMapTest() {Params params = new Params();params.setId(1);params.setName("gangge");return openFeignTestService.springQueryMapProviderTest(params);
}

结果

在这里插入图片描述

复杂对象传递

对象套对象的情况,准备一个ComplexObjectResult对象(提供者和消费者都需要创建)

ComplexObject

public class ComplexObject {private Params params;public Params getParams() {return params;}public void setParams(Params params) {this.params = params;}
}

Result

public class Result {private Integer code;private String describe;public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getDescribe() {return describe;}public void setDescribe(String describe) {this.describe = describe;}
}

在服务提供方编写接口,接受消费者调用,后返回Result对象

@PostMapping("/complexObjectProviderTest")
public Result complexObjectProviderTest(@RequestBody ComplexObject complexObject) {Result result = new Result();result.setCode(200);result.setDescribe("#complexObjectProviderTest" + complexObject.getParams().getName() + complexObject.getParams().getId());return result;
}

消费者声明客户端接口和fallback操作

@PostMapping("/complexObjectProviderTest")
public Result complexObjectProviderTest(@RequestBody ComplexObject complexObject);@Override
public Result complexObjectProviderTest(ComplexObject complexObject) {return null;
}

返回Result对象**

@PostMapping("/complexObjectProviderTest")
public Result complexObjectProviderTest(@RequestBody ComplexObject complexObject) {Result result = new Result();result.setCode(200);result.setDescribe("#complexObjectProviderTest" + complexObject.getParams().getName() + complexObject.getParams().getId());return result;
}

消费者声明客户端接口和fallback操作

@PostMapping("/complexObjectProviderTest")
public Result complexObjectProviderTest(@RequestBody ComplexObject complexObject);@Override
public Result complexObjectProviderTest(ComplexObject complexObject) {return null;
}

复杂对象时@RequestBody注解完全可以,但是只能有一个@RequestBody的参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/118954.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件测试/测试开发丨Pytest和Allure报告 学习笔记

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/26755 Pytest 命名规则 类型规则文件test_开头 或者 _test 结尾类Test 开头方法/函数test_开头注意&#xff1a;测试类中不可以添加__init__构造函数 注…

使用 BERT 进行文本分类 (03/3)

一、说明 在使用BERT&#xff08;2&#xff09;进行文本分类时&#xff0c;我们讨论了什么是PyTorch以及如何预处理我们的数据&#xff0c;以便可以使用BERT模型对其进行分析。在这篇文章中&#xff0c;我将向您展示如何训练分类器并对其进行评估。 二、准备数据的又一个步骤 …

IDEA中Run/Debug Configurations添加VM options和Program arguments

1. 现象描述 我在我的IDEA当中打开配置模板后&#xff0c;发现没有VM options和Program arguments&#xff0c;也就是虚拟机选项和程序实参这两项&#xff0c;导致我不能配置系统属性参数和命令行参数&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff0…

【vue2第十一章】v-model的原理详解 与 如何使用v-model对父子组件的value绑定 和修饰符.sync

v-model的原理详解 v-model的本质就是一个语法糖&#xff0c;实际上就是 :value"msg" 与 input"msg $event.target.value" 的简写。 :value"msg" 从数据单向绑定到input框&#xff0c;当data数据中的msg内容一旦改变&#xff0c;而input框数据…

Matlab 基本教程

1 清空环境变量及命令 clear all % 清除Workspace 中的所有变量 clc % 清除Command Windows 中的所有命令 2 变量命令规则 &#xff08;1&#xff09;变量名长度不超过63位 &#xff08;2&#xff09;变量名以字母开头&#xff0c; 可以由字母、数字和下划线…

自定义类型:结构体、枚举、联合

目录 结构体 结构体的基础知识 结构的声明 特殊的声明 结构体的自引用 结构体变量的定义和初始化 结构体内存对齐 修改默认对齐数 结构体传参 位段 什么是位段 位段的内存分配 位段的跨平台问题 位段的应用 枚举 枚举类型的定义 枚举的优点 联合体&#xff08;共…

CLFS信息泄露漏洞CVE-2023-28266分析

引用 这篇文章的目的是介绍今年4月发布的CLFS信息泄露漏洞CVE-2023-28266分析. 文章目录 引用简介CVE-2023-28266漏洞分析CVE-2023-28266调试过程漏洞复现相关引用参与贡献 简介 文章结合了逆向代码和调试结果分析了CVE-2023-28266漏洞利用过程和漏洞成因. CVE-2023-28266漏洞…

stm32之27.iic协议oled显示

屏幕如果无法点亮&#xff0c;需要用GPIO_OType_PP推挽输出&#xff0c;加并上拉电阻 1.显示字符串代码 2.显示图片代码&#xff08;unsigned强制转换&#xff08;char*&#xff09;&#xff09; 汉字显示

友元(个人学习笔记黑马学习)

1、全局函数做友元 #include <iostream> using namespace std; #include <string>//建筑物类 class Building {//goodGay全局函数是 Building好朋友 可以访问Building中私有成员friend void goodGay(Building* building);public:Building() {m_SittingRoom "…

SpringMVC

学习流程图&#xff1a; 四个学习模块&#xff1a; 1、SpringMVC入门 2、请求与响应 3、rest风格 4、ssm整合 5、拦截器 第一章、SpringMVC入门 1、简介 SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架。 SpringMVC的开发步骤&#xff1a; …

vscode调教配置:快捷修复和格式化代码

配置vscode快捷键&#xff0c;让你像使用idea一样使用vscode&#xff0c;我们最常用的两个功能就是格式化代码和快捷修复&#xff0c;所以这里修改一下快捷修复和格式化代码的快捷键。 在设置中&#xff0c;找到快捷键配置&#xff1a; 然后搜索&#xff1a;快捷修复 在快捷键…

即时通讯开发中的性能优化技巧

即时通讯开发在如今的数字化社会中扮演着重要角色&#xff0c;然而&#xff0c;随着用户对即时通讯应用的需求不断增长&#xff0c;开发者们面临着使其应用保持高性能和可靠性的挑战。本文将探讨即时通讯开发中关键的性能优化技巧&#xff0c;帮助开发者们提升应用的用户体验和…

基于Java的OA办公管理系统,Spring Boot框架,vue技术,mysql数据库,前台+后台,完美运行,有一万一千字论文。

基于Java的OA办公管理系统&#xff0c;Spring Boot框架&#xff0c;vue技术&#xff0c;mysql数据库&#xff0c;前台后台&#xff0c;完美运行&#xff0c;有一万一千字论文。 系统中的功能模块主要是实现管理员和员工的管理&#xff1b; 管理员&#xff1a;个人中心、普通员工…

c语言每日一练(13)

前言&#xff1a;每日一练系列&#xff0c;每一期都包含5道选择题&#xff0c;2道编程题&#xff0c;博主会尽可能详细地进行讲解&#xff0c;令初学者也能听的清晰。每日一练系列会持续更新&#xff0c;上学期间将看学业情况更新。 五道选择题&#xff1a; 1、程序运行的结果…

图文详解PhPStudy安装教程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 官方下载 请在PhPStudy官方网站下载安装文件&#xff0c;官方链接如下&#xff1a;https://m.xp.cn/linux.html&#xff1b;图示如下&#xff1a; 请下载PhPStudy安装文件…

SpringCloudAlibaba Gateway(一)简单集成

SpringCloudAlibaba Gateway(一)简单集成 随着服务模块的增加&#xff0c;一定会产生多个接口地址&#xff0c;那么客户端调用多个接口只能使用多个地址&#xff0c;维护多个地址是很不方便的&#xff0c;这个时候就需要统一服务地址。同时也可以进行统一认证鉴权的需求。那么服…

golong基础相关操作--一

package main//go语言以包作为管理单位&#xff0c;每个文件必须先声明包 //程序必须有一个main包 // 导入包&#xff0c;必须要要使用 // 变量声明了&#xff0c;必须要使用 import ("fmt" )/* * 包内部的变量 */ var aa 3var ss "kkk"var bb truevar …

使用Python对数据的操作转换

1、列表加值转字典 在Python中&#xff0c;将列表的值转换为字典的键可以使用以下代码&#xff1a; myList ["name", "age", "location"] myDict {k: None for k in myList} print(myDict) 输出&#xff1a; {name: None, age: None, loca…

EasyExcel导出模板实现下拉选(解决下拉超过50个限制)

学习地址&#xff1a;https://d9bp4nr5ye.feishu.cn/wiki/O3obweIbgi2Rk1ksXJncpClTnAfB站视频&#xff1a;https://www.bilibili.com/video/BV1H34y1T7Lm 先来看看最终实现效果&#xff0c;如果效果是你想要的&#xff0c;再看看实现逻辑。 EasyExcel本身是支持设置下拉校验的…

小程序中如何给会员卡设置到期时间

通过设置会员卡到期时间&#xff0c;可以有效地管理会员卡的使用周期&#xff0c;提供更好的会员服务体验。下面将介绍一种常见的给会员卡设置到期时间的方法。 1. 找到指定的会员卡。在管理员后台->会员管理处&#xff0c;找到需要设置到期时间的会员卡。也支持对会员卡按…