[SpringCloud] Feign 与 Gateway 简介

目录

一、Feign 简介

1、RestTemplate 远程调用中存在的问题

2、定义和使用 Feign 客户端

3、Feign 自定义配置

4、Feign 性能优化

5、Feign 最佳实践

6、Feign 使用问题汇总

二、Gateway 网关简介

1、搭建网关服务

2、路由断言工厂

3、路由的过滤器配置

4、全局过滤器

5、过滤器链执行顺序

6、网关的 cors 跨域配置

7、Gateway 网关使用问题汇总


一、Feign 简介

Feign 是 Netflix 开发的声明式、模板化的 Http 客户端,Feign 可以帮助我们更快捷、优雅地调用Http API。

  • Feign 是在 Ribbon 的基础上进行了一次改进,是一个使用起来更加方便的 HTTP 客户端。
  • SpringCloud 对 Feign 进行了增强,使 Feign 支持了 Spring MVC 注解,并整合了 Ribbon 和 Eureka,集成了服务发现和负载均衡,从而让 Feign 的使用更加方便。

1、RestTemplate 远程调用中存在的问题

该远程调用的代码有以下问题:

  • 代码可读性差,编程体验不统一;
  • 参数复杂,URL 难以维护;

2、定义和使用 Feign 客户端

在 SpringCloud 中,使用 Feign 非常简单,创建一个 Interface,并在接口上添加一些注解,代码就完成了。 

(1)引入依赖

  • 给需要远程调用的模块,引入 openfeign 起步依赖;

(2)添加 @EnableFeignClients 注解

  • 给需要远程调用的启动类,添加 @EnableFeignClients 注解;

(3)编写 Feign 客户端

  • 添加 @FeignClient 和 @GetMapping 注解; 

上述注解声明了如下信息:

  • 服务名称:user-service;
  • 请求方式:get;
  • 请求路径:/user/{userId};
  • 请求参数:String userId;
  • 返回值类型:User;

(4)OrderService 远程调用过程

该远程调用过程,就好像平常处理请求的逆过程:

  • OrderService 将 userId 传递给接口中的方法;
  • queryUserById 方法再将参数赋值给请求路径中的占位符 {userId};
  • 然后再通过 get 请求向 UserController 发送请求;
  • 最终获得 User 对象信息;

3、Feign 自定义配置

Spring 虽然帮我们做好了配置,但是也允许我们修改默认配置。

配置 Feign 日志有 2 种方式:

(1)application/bootstrap 配置文件方式

  • 注意:logging.level 属性值需要改为 trace; 

(2)Java 代码方式

4、Feign 性能优化

Feign 底层客户端实现:

  • URLConnection:默认使用,java 原生 jdk,性能较差,不支持连接池;
  • Apache HttpClient:支持连接池;(推荐)
  • OKHttp:支持连接池;(推荐)

对 Feign 的性能优化,最重要的一点就是对底层实现的改变。

因此优化 Feign 的性能主要包括:

  • 使用连接池代替默认的 URLConnection;
  • 日志级别,最好用 basic 或 none;(因为开启日志也需要占用较多资源)

下面以 HttpClient 为例子,说明性能优化的步骤:

(1)引入依赖

  • httpClient 已经被 Spring 管理好版本了,不需要指定版本;

(2)修改 application 配置文件

  • 将 feign.httpclient.enabled 的属性值改为 true,表明底层使用 httpclient;

5、Feign 最佳实践

最佳实践是指,企业开发过程中,总结设计缺点,得出的一种相对比较好的使用方式。

通常会用到 2 种方式,各有利弊,按自己的需求使用:

  • 继承:给消费者的 FeignClient 和提供者的 controller 定义统一的父接口,然后实现接口;
  • 比如 order 模块要调用 user 模块的服务,就定义 UserClient 接口,继承 UserAPI;
  • 缺点:耦合度高;
  • 优点:遵从了契约;

  • 抽取:将 FeignClient 抽取为独立模块,并且把接口有关的 POJO、默认的 Feign 配置都放到这个模块中,提供给所有消费者使用;
  • 缺点:消费者可能会引入很多用不到的 api;
  • 优点:耦合度低,层次分明;

我个人更喜欢第二种抽取的方式,下面使用这种方式做一个例子。

(1)创建 feign-api 模块

  • 在 feign-api 模块中引入 feign 的起步依赖;

  • 将消费者模块中对提供者模块所需的 Client、Pojo,以及 Config 类都移动到 feign-api 中;

(2)引入 feign-api 模块

  • 在消费者 order-service 模块中,引入 feign-api 模块;

(3)消除报错

  • 将 order-service 模块内原来依赖 pojo、config、client 的类,修改为 feign-api 模块内的类;

  • 由于 order-service 模块的 application 启动类无法扫描到 feign-api 模块下的 Client 的 Bean 对象,因此会出现如下报错:

  • 需要在 @EnableFeignClients 中加入 clients 属性;

6、Feign 使用问题汇总

(1)Did you forget to include spring-cloud-starter-loadbalancer?

出错原因: 

  • SpringCloud Feign 在 Hoxton.M2 RELEASED 版本之后不再使用 Ribbon,而是使用 spring-cloud-loadbalancer,所以在不引入 spring-cloud-loadbalancer 的情况下会报错。

参考了很多解决方法,主要是要区别版本问题:

包含 RELEASE 关键字的版本中,只有下面这样操作才能使用:

  • 首先排除 ribbon 的起步依赖,排除位置在消费者依赖的服务提供者的 dependency;
  • 添加 loadBalancer 依赖;

而在 2021 及更新版本中(也就是没有 RELEASE 关键字的版本),只需要如下操作:

  • 引入 loadBalancer 依赖;
  • 不需要排除 ribbon 的起步依赖;

二、Gateway 网关简介

为什么需要网关?

  • 如果没有网关,那么所有人都可以访问我们所有的服务,但是有很多服务其实是不能对外公开的。
  • 需要使用网关进行身份验证,通过后才能访问敏感服务。
  • 一切请求需要先通过网关,才能到微服务。

因此,网关有如下功能:

  • 身份认证和权限校验;
  • 服务路由、负载均衡;(也就是能知道将请求送到哪个微服务)
  • 限制请求流量;

SpringCloud 提供了 2 个组件实现网关功能:

  • gateway;(新版本)
  • zuul;(早期版本)

Zuul 是基于 Servlet 的实现,属于阻塞式编程。

而 SpringCloudGateway 则是基于 Spring5 中提供的 WebFlux,属于响应式编程的实现,具备更好的性能。

1、搭建网关服务

(1)创建 gateway 模块

  • 创建一个新的模块专门用于网关:gateway-module,需要 SpringBoot 启动类;
  • 引入 SpringCloudGateway 起步依赖;
  • 引入 Nacos 服务发现依赖;

(2)编写路由配置以及 Nacos 地址

  • gateway 中的 routes 属性之前的配置,目的是为了让 gateway 将服务注册到 nacos;
  • gateway 中的 routes 属性之后的配置,指明了可以使用的 service 路由;
  • id:表示这个路由的名字,与其他属性无关;
  • uri:表示路由目标地址,其中 lb 表示负载均衡,后面跟着服务的 name;
  • predicates:指定路由规则,符合规则就可以放行;

(3)测试网关功能

  • 启动 gateway 的 application;
  • 发起请求:localhost:10010/order/queryOrderById/1;
  • 这个请求中,order-service 模块会调用 user-service 的服务;

  • 访问失败,说明我们的网关起作用了,因为我们没有为网关配置 order-service 的路由;

  • 添加对 order-service 的服务的路由后,就可以从 gateway 访问 order 的服务了;

2、路由断言工厂

路由断言工厂 Route Predicate Factory,作用是:

  • 我们在配置文件中写的 predicates 断言规则只是字符串,这些字符串会被 Predicate Factory 读取并解析为路由判断的条件。
  • 每种规则都有各自的断言工厂去解析,比如 Path 有 PathRoutePredicateFactory 断言工厂;

下面以 After 举一个例子:

(1)添加断言规则 After

  • After 断言规则,规定在这个时间之后,才能进行访问; 

(2)访问 order 的服务

  • 发送请求 /order/queryOrderById/1;
  • 理向情况应该是:无法访问;

  • 修改断言规则的时间为:2020-12-31,重启 gateway 模块;

  • 再次发起请求,就可以访问了;

3、路由的过滤器配置

路由过滤器是:GatewayFilter。

  • GatewayFilter 是网关中提供的一种过滤器,可以对进入网关的请求微服务返回的响应做处理。

在这个过程中,过滤器就可对请求和响应做出各种各样的处理,这样往下游传递的数据中,就包含了修改后的信息。

具体有什么样的操作,就要看使用哪个过滤器工厂:

下面我们以添加一个请求头为例子:

(1)修改 application 配置文件

  • 给 routes 中的一个路由添加 filters 属性;
  • filters 中添加:- AddRequestHeader=[key],[value];

(2)编写 Controller,获取请求头信息

  • 既然在 filter 中设置了 header:orderStatus=001;
  • 那么请求传递到 Controller 后,一定可以获取到这个头信息;

  • 访问 /order/queryOrderById/1,查看控制台输出;

(3)编写默认过滤器 default-filter

如果我们想为所有的请求都添加 header 信息,也不需要给每一个路由都写上 filters。

  • 只需要在 routes 同级下,添加 default-filter 属性;
  • 给 default-filter 属性添加:- AddRequestHeader=[key],[value] 等属性值;

  • 访问 /order/queryOrderById/1,查看控制台输出;

4、全局过滤器

全局过滤器是:GlobalFilter。

  • 全局过滤器的作用:处理一切进入网关的请求和微服务响应,与 GatewayFilter 的作用一样,只是作用范围不同。
  • 其中,GatewayFilter 通过配置定义,运行逻辑是固定的。(官方定义)
  • 而 GlobalFilter 的运行逻辑需要自己写代码实现。(自定义)

需求

定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

  • 参数中是否有 authorization;
  • authorization 参数值是否为 admin;
  • 如果同时满足则放行,否则拦截;

(1)定义实现类

  • 创建 AuthorFilter 实现类,实现 GlobalFilter 接口;
  • exchange:请求上下文,里面可以获取Request. Response等信息;
  • chain:用来把请求委托给下一个过滤器;
  •  Nono<Void>:返回表示当前过滤器业务结束

(2)定义 filter 方法的运行逻辑

  • 添加 @Component;
  • 添加 @Order,方便多过滤器时指定顺序;
  • 网关中采用的都是基于 WebFlux(响应式编程)的 API,因此使用上与 ServletAPI 不同;
@Order(-1)
@Component
public class AuthorFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 1.获取请求参数ServerHttpRequest request = exchange.getRequest();MultiValueMap<String, String> params = request.getQueryParams();// 2.获取请求参数中的 author 参数值String author = params.getFirst("author");// 3.判断是否等于 adminif (author.equalsIgnoreCase("admin")) {// 放行return chain.filter(exchange);}// 4.不相等,获取响应ServerHttpResponse response = exchange.getResponse();// 4.1.设置状态码,401表示未登录response.setStatusCode(HttpStatus.UNAUTHORIZED);// 4.2.拦截请求return response.setComplete();}
}

(3)启动 gateway 的 application

  • 访问 /order/queryOrderById/1/author=admin111,先使用错误的 authon 参数值;
  • 发现返回了 401;

  • 访问 /order/queryOrderById/1/author=admin,使用正确的 authon 参数值;
  • 可以正常访问

5、过滤器链执行顺序

请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter。

请求路由后,会将当前路由过滤器DefaultFilterGlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器。

过滤器执行顺序:

  • 每一个过滤器都必须指定一个 int 类型的 order 值:order 值越小,优先级越高,执行顺序越靠前;
  • GlobalFilter 通过实现 Ordered 接口,或者添加 @Order 注解来指定 order 值,由我们自己指定;
  • 路由过滤器和 defaultFilter 的 order 由 Spring 官方指定,默认是按照声明顺序从 1 递增;
  • 当过滤器的 order 值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter 的顺序执行;

6、网关的 cors 跨域配置

由于一些页面可能需要从微服务中获取某些数据,此时需要发起 AJAX 请求,那么这就可能属于跨域请求的范畴。(一般我们的 web 页面端口都不会与微服务的相同,所以请求基本上都是跨域请求)

跨域请求不需要在微服务中处理,只需要在网关中处理即可。

跨域:域名不一致就是跨域,主要包括:

  • 域名不同:www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com;
  • 域名相同,端口不同:localhost:8080 和 localhost:8081

跨域问题的 2 个要素:

  • 浏览器、服务端:浏览器禁止请求向服务端发起跨域 ajax 请求,请求会被拦截;
  • 解决方案:CORS;

需求:

  • 使用 localhost:8090 发起请求,8090 发送的是 AJAX 的 GET 请求。
  • 8090 发起的 AJAX 请求需要通过网关,在 AJAX 的目标地址中要用 10010 端口;

(1)编写 gateway 的配置文件

  • 各个属性的作用都写在注释中了;

(2)端口 8090 的 AJAX 请求

  • 这里使用 JQuery 发起 AJAX 请求,传递参数为 author=admin;
  • 这里参数是必须传递的,因为发起的请求目标地址是要通过网关的,需要鉴权;
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="JQuery-3.7.0.js"></script><script type="text/javascript">$(function() {$("#ajaxButton").click(function() {$.ajax({url:"http://localhost:10010/order/queryOrderById/1",data: {author : "admin"},type: "get",dataType: "json",success: function(data) {console.log(data);}});});});</script>
</head>
<body><a href="http://localhost:10010/order/queryOrderById/1?author=admin"> 发起普通GET请求 </a><input id="ajaxButton" type="button" value="发起 ajax 请求"/>
</body>
  • 发起请求,可以在控制台看到返回的数据;

  • 而如果我们用 <a> 来请求,是会跳转到 10010 得页面的,这就不算跨域请求了;

7、Gateway 网关使用问题汇总

(1)搭建网关服务时,报错 503

这是因为在 Spring Cloud 2020 版本以后,默认移除了对 Netflix 的依赖,其中就包括 Ribbon,官方默认推荐使用 Spring Cloud Loadbalancer 正式替换 Ribbon,并成为了 Spring Cloud 负载均衡器的唯一实现。

Loadbalancer 依赖:

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

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

相关文章

【PID专题】控制算法PID之比例控制(P)的原理和示例代码

PID是“比例-积分-微分”的缩写&#xff0c;是一种广泛用于控制系统的反馈控制算法。PID控制器根据测量值与期望值之间的误差来调整控制器的输出&#xff0c;以使系统稳定并尽可能接近期望值。下面是PID中P&#xff08;比例控制&#xff09;的基本介绍&#xff1a; 比例&#x…

springweb flux拦截请求获取参数和方法做接口签名防重放校验

在给spring webflux做接口签名、防重放的时候&#xff0c;往往需要获取请求参数&#xff0c;请求方法等&#xff0c;而spring webflux无法像spring mvc那样好获取&#xff0c;这里根据之前的实践特地说明一下&#xff1a; 总体思路&#xff1a; 1、利用过滤器&#xff0c;从原…

关于CSS的几种字体悬浮的设置方法

关于CSS的几种字体悬浮的设置方法 1. 鼠标放上动态的2. 静态的&#xff08;位置看上悬浮&#xff09;2.1 参考QQ邮箱2.2 参考知乎 1. 鼠标放上动态的 效果如下&#xff1a; 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><met…

<多线程章节八> 单例模式中的饿汉模式与懒汉模式的讲解,以及懒汉模式中容易引起的Bug

&#x1f490;专栏导读 本篇文章收录于多线程&#xff0c;也欢迎翻阅博主的其他文章&#xff0c;可能也会让你有不一样的收获&#x1f604; &#x1f337;JavaSE &#x1f342;多线程 &#x1f33e;数据结构 文章目录 &#x1f490;专栏导读&#x1f4a1;饿汉模式&#x1f4a1;…

从 Seq2Seq 到 Attention:彻底改变序列建模

探究Attention机制和意力的起源。 简介 在这篇博文[1]中&#xff0c;将讨论注意力机制的起源&#xff0c;然后介绍第一篇将注意力用于神经机器翻译的论文。由于上下文压缩、短期记忆限制和偏差&#xff0c;具有 2 个 RNN 的 Seq2Seq 模型失败了。该模型的 BLEU 分数随着序列长度…

【VPX630】青翼 基于KU115 FPGA+C6678 DSP的6U VPX通用超宽带实时信号处理平台

板卡概述 VPX630是一款基于6U VPX总线架构的高速信号处理平台&#xff0c;该平台采用一片Xilinx的Kintex UltraScale系列FPGA&#xff08;XCKU115&#xff09;作为主处理器&#xff0c;完成复杂的数据采集、回放以及实时信号处理算法。采用一片带有ARM内核的高性能嵌入式处理器…

【深度学习】pytorch——快速入门

笔记为自我总结整理的学习笔记&#xff0c;若有错误欢迎指出哟~ pytorch快速入门 简介张量&#xff08;Tensor&#xff09;操作创建张量向量拷贝张量维度张量加法函数名后面带下划线 _ 的函数索引和切片Tensor和Numpy的数组之间的转换张量&#xff08;tensor&#xff09;与标量…

三十九、CANdelaStudio实践-19服务(ReadDTCInformation)

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的19服务(ReadDTCInformation)编辑,欢迎…

基于STM32C8T6的智能蓝牙小车控制设计

**单片机设计介绍&#xff0c;1655基于STM32C8T6的智能蓝牙小车控制设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计五、 程序文档 六、 结论七、 文章目录 一 概要 基于STM32C8T6的智能蓝牙小车控制设计是基于STM32微控制器和蓝牙模块开发的一种小型智能车辆控制系统…

力扣刷题-队列-滑动窗口最大值

239. 滑动窗口最大值 给定一个数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回滑动窗口中的最大值。 进阶&#xff1a; 在线性时间复杂度内解决此题&#xff1f; …

算法leetcode|86. 分隔链表(rust重拳出击)

文章目录 86. 分隔链表&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 86. 分隔链表&#xff1a; 给你一个链表的头节点 head 和一个特…

ubuntu 22.04 源码安装 apollo 8.0

对于其他的关于GPU的安装包需求&#xff0c;这里不再列出&#xff0c;因为我之前安装过&#xff0c;偷个懒就不写了&#xff0c;哈哈哈哈1, 安装docker 安装docker命令(这里的安装命令都是在docker官网,还有安装包)&#xff1a; 1&#xff0c; 设置docker的apt仓库 # Add Do…

IDEA 如何运行 SpringBoot 项目

步骤一&#xff1a;配置 Maven 第一步&#xff1a;用 IDEA 打开项目&#xff0c;准备配置 maven 环境 &#xff0c;当然如果本地没有提前配置好 maven&#xff0c;就用 IDEA 默认的配置即可 配置 maven 步骤 情况 1&#xff1a;如果本地没有配置过 maven&#xff0c;可以保持如…

Jetpack:025-Jetpack中的多点触控事件

文章目录 1. 概念介绍2. 使用方法2.1 缩放事件2.2 旋转事件2.3 平移事件2.4 综合事件 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中滚动事件相关的内容&#xff0c;本章回中主要介绍 多点解控事件。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xf…

HTML基本概念:

HTML简介&#xff1a; 超文本标记语言&#xff08;英语&#xff1a;HyperText Markup Language&#xff0c;简称&#xff1a;HTML&#xff09;是一种用于创建网页的标准标记语言。 1&#xff09;、HTML 是用来描述网页的一种语言。 2&#xff09;、HTML 不是一种编程语言&am…

笔记本电脑搜索不到wifi6 无线路由器信号

路由器更换成wifi6 无线路由器后&#xff0c;手机能搜索到这个无线信号&#xff0c;但是笔记本搜索不到这个无线信号&#xff0c;后网上搜索后发现是无线网卡驱动问题&#xff0c;很多无线网卡使用的是Intel芯片&#xff0c;Intel就此发布了公告&#xff0c;升级驱动就可以彻底…

我和云栖有个约会

开端&#xff0c;似曾相识的云栖 2023年阿里云云栖大会在云栖小镇举办&#xff0c;云栖小镇&#xff1f;在2020年的时候&#xff0c;曾经来过这里参加竞赛。时隔三年&#xff0c;身份变换&#xff0c;以开发者的身份&#xff0c;收到阿里云开发者社区的邀请&#xff0c;正好有…

linux 报错

输入 pip install -U openmim报错 有可能是服务器在其他国家&#xff0c;需要手动设置 把这三行复制到~/.bashrc里 export http_proxyhttp://127.0.0.1:3128 export https_proxy${http_proxy} export ftp_proxy${http_proxy}source ~/.bashrc

第57篇-某钩招聘网站加密参数分析【2023-10-31】

声明:该专栏涉及的所有案例均为学习使用,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!如有侵权,请私信联系本人删帖! 文章目录 一、前言二、网站分析1.X-S-HEADER参数2.请求参数data3.响应机密值data一、前言 网址: aHR0cHM6Ly93d3cubGFnb3UuY29t…

[NSSRound#6 Team]check(Revenge)

文章目录 考点tarfile文件覆盖漏洞&#xff08;CVE-2007-4559&#xff09;PIN码计算 解题过程非预期解预期解 考点 tarfile文件覆盖漏洞&#xff08;CVE-2007-4559&#xff09; Python 中 tarfile 模块中的extract、extractFile和extractall 函数中的目录遍历漏洞 允许 用户协…