微服务_Spring Cloud_OpenFeign与网关
1. RestTemplate存在问题

虽说RestTemplate 对HTTP封装后, 已经⽐直接使⽤HTTPClient简单⽅便很多, 但是还存在⼀些问题.
需要拼接URL, 灵活性⾼, 但是封装臃肿, URL复杂时, 容易出错;代码可读性差, ⻛格不统⼀.
微服务之间的通信⽅式, 通常有两种: RPC 和 HTTP.
在SpringCloud中, 默认是使⽤HTTP来进⾏微服务的通信, 最常⽤的实现形式有两种:
RestTemplate 和OpenFeign
2.OpenFeign 完整知识点解析
一、基础定义
OpenFeign 是声明式 Web 服务客户端,用于微服务之间远程 HTTP 调用,特点: 只需要定义接口 + 添加注解,就能像调用本地 Service 一样调用远程微服务接口,写法风格和 Controller 完全一致,屏蔽了 RestTemplate、原生 HttpClient 拼接 URL、处理请求的繁琐过程。
二、前身
OpenFeign 基于 Netflix Feign 二次开发而来:
- 原生 Feign:Netflix 开源,只实现声明式调用,不自带负载均衡;
- OpenFeign:Spring Cloud 整合增强版本,内置集成 SpringCloud LoadBalancer(旧版本整合 Ribbon),天然具备负载均衡能力,是目前主流方案。
3.OpenFeign的使用
1. 引入 Maven 依赖
xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2. 启动类开启 Feign 扫描
在调用方服务(示例为 order-service 订单服务)启动类添加 @EnableFeignClients 注解:
@EnableFeignClients // 开启OpenFeign,自动扫描带@FeignClient的接口
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
-
作用:Spring 启动时自动扫描所有
@FeignClient接口,生成代理对象注入容器。
3. 编写 Feign 客户端接口(声明式远程接口)

注解说明:
-
@FeignClient(value = "product-service")-
value:被调用服务的服务名称(Nacos/Eureka 注册的服务名),Feign 结合负载均衡自动完成服务发现。
-
-
path = "/product":目标服务所有接口的公共前缀,等价于 Controller 上的@RequestMapping("/product")。 -
接口内的方法写法、注解、入参规则必须和被调用服务的 Controller 完全一致。

4.OpenFeign参数传递
1.在product-service服务定义多个不同参数传递接口,并进行测试

2.在ProductApi编写客户端接口

3.在order-service编写接口调用客户端接口进行测试

5.OpenFein最佳实践
最佳实践1
一、解决的痛点
常规写法里:, Feign的客⼾端与服务提供者的controller代码⾮常相似, Feign的客⼾端与服务提供者的controller代码⾮常相似,服务提供者 Controller、消费者 Feign 接口 两份代码要手写一模一样的接口签名,路径、注解、参数极易写错、维护繁琐。 Feign 继承方案统一抽取公共接口,两端复用,消除重复代码。
二、整体架构(对应你新建的 product-api 模块)
-
公共模块 product-api(打成公共 jar) 存放标准父接口
ProductApi,定义全部接口签名、请求注解(@GetMapping、@PathVariable等),将打好的 jar 安装到本机 Maven 本地仓库;
-
服务提供者 product-service Controller 实现
product-api里的公共接口,只写业务逻辑即可,不用重复写接口注解与路径。
-
服务消费者 order-service Feign 客户端接口 继承
product-api里的公共接口,仅添加@FeignClient注解。
最佳实践2
Feign 抽取⽅式
1.建公共模块 product-api,将ProductApi和ProductInfo移入,打成公共 jar

2.OrderController类
3.OderService 类

4.测试
部署时需修改公共模块 product-api的pom文件

网关
- 已有技术现状:Eureka/Nacos 实现服务注册发现、SpringCloud LoadBalance 完成负载均衡、OpenFeign 实现远程调用。
- 现存痛点:微服务各个接口直接对外开放,每个微服务都要单独实现权限校验逻辑;一旦校验规则变更,需要修改所有服务,维护繁琐。
- 通俗类比:
- 单体架构:单人处理身份核验 + 业务办理;
- 微服务架构:多个部门各自都要核验身份,效率低、流程冗余;
- 解决方案:引入API 网关充当统一前台,由网关统一完成身份、权限校验,校验放行后内部微服务无需重复校验,解决重复鉴权、维护麻烦的问题。
网关四大核心功能简述
1. 权限控制
网关作为整个微服务集群的统一入口,集中完成身份、权限校验;校验失败直接拦截请求,校验通过才放行,以此避免每个微服务重复编写鉴权逻辑。
2. 动态路由
所有外部请求统一抵达网关,网关本身不处理业务逻辑,按照预设规则将请求转发至对应的后端微服务。
3. 负载均衡
若目标微服务部署了多个实例,网关会自动进行负载分发,将请求分配给不同实例,实现流量均分。
4. 限流
当接口访问流量突增时,网关依照配置的流量阈值放行请求,超额流量直接拦截,防止后端服务因流量冲击崩溃。
常见网关方案简述
业界主流开源网关包含 Nginx、Kong、Zuul、Spring Cloud Gateway 等,课程重点对比 Zuul 与 Spring Cloud Gateway:
一、Zuul
- 归属:Netflix 开源网关组件,属于 Spring Cloud Netflix 体系,可搭配 Eureka、Ribbon、Hystrix 协同工作。
- 历史地位:Spring Cloud Finchley 版本之前,是官方推荐网关方案。
- 现状:Netflix 在 2018 年停止为 Zuul 迭代新功能,仅做基础维护,现已逐步被替代。
二、Spring Cloud Gateway
- 定位:Spring Cloud 官方推出的全新网关,基于 Spring + SpringBoot 开发,设计初衷就是用来替代 Zuul。
- 能力:负责请求转发,同时统一提供安全校验、监控、容错等高可用横切能力。
- 性能优势:官方压测数据显示,其每秒处理请求数(RPS)是 Zuul 的 1.6 倍,性能更强。
Spring Cloud GatewayD的使用
1.引入依赖
<dependencies>
<!--⽹关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--基于nacos实现服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
2.编写启动类
package com.bite.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class,args);
}
}
3. 添加Gateway的路由配置,创建application.yml⽂件,添加如下配置:
server:
port: 10030
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes: #网关路由配置
- id: order-service #路由Id,自定义唯一即可
uri: lb://order-service #目的服务地址
predicates: #路由条件
- Path=/order/**,/feign/**
- id: product-service
uri: lb://product-service
predicates:
- Path=/product/**
4.启动测试


(1)Route Predicate Factories(路由断言工厂)
1.Predict
Predict是一个函数式编程接口,接收一个参数并返回一个布尔值,用于条件过滤,请求参数的校验
代码演示
定义一个Predict并使用



其他方法
内置函数

Lambda方法

predict其他方法
| 方法 | 作用 | 说明 | |||
|---|---|---|---|---|---|
test(T t) | 执行判断逻辑 | 抽象方法,传入待判断对象,返回 true/false,所有判断最终都要调用test() | |||
and(Predicate other) | 短路与 && | 两个条件同时成立才为 true,短路特性:第一个条件 false,后面不再执行 | |||
or(Predicate other) | 短路或 ` |
| ` | ||
negate() | 逻辑非 ! | 把当前判断结果取反,true 变 false,false 变 true | |||
isEqual(Object targetRef) | 静态方法,对象相等比较 | 静态方法!使用Predicate.isEqual(目标值),内部用Objects.equals,支持 null 值比较 |
Route Predicate Factories-路由断言工厂
Predicate 在这里叫路由谓词 / 断言,作用:匹配 HTTP 请求,只有断言全部满足,当前路由才生效;多个断言之间默认是
and(同时满足)关系。
| 断言工厂 | 作用 | 配置示例 |
|---|---|---|
After | 匹配指定时间之后到来的请求(ZonedDateTime 带时区时间) | After=2017-01-20T17:42:47.789-07:00[America/Denver] |
Before | 匹配指定时间之前的请求 | Before=2026-12-01T00:00:00+08:00[Asia/Shanghai] |
Between | 匹配在两个时间区间内的请求 | Between=时间1,时间2 |
Path | 匹配请求 URL 路径,支持通配符** | Path=/product/** |
Method | 匹配 HTTP 请求方法(GET/POST/PUT 等) | Method=GET |
Query | 匹配请求查询参数 | Query=name |
Header | 匹配请求头 | Header=X‑Request‑Id, \d+ |
举例After和path:

- After=2026-08-10T16:09:08.009510400+08:00[Asia/Shanghai]表示只有在这个时间之后才能正常访问
(2)SpringCloud Gateway Filter(网关过滤器)
1. Filter 作用
对进入网关的请求做链式处理,实现鉴权、限流、超时控制、请求参数修改、响应处理等逻辑。
Predicate(断言):决定请求匹配哪一条路由; Filter(过滤器):在请求转发之前 / 之后增加业务逻辑。
2. Filter 的执行时机:Pre / Post
表格
| 类型 | 执行时机 | 典型场景 |
|---|---|---|
| Pre | 请求转发到微服务之前执行 | 鉴权、校验、限流、修改请求头 / 请求参数 |
| Post | 微服务执行完毕,返回给客户端之前执行 | 修改响应头、日志记录、统一返回结果处理 |
3. 按照作用范围分类
① GatewayFilter(局部过滤器)
-
生效范围:只对某一个 / 一组路由生效
-
配置位置:写在 yml 的对应
routes路由下面 -
内置实现:
AddRequestParameterGatewayFilterFactory等,直接在配置写工厂前缀即可开启功能。
② GlobalFilter(全局过滤器)
-
生效范围:对网关全部路由、所有请求都生效
-
使用方式:一般写 Java 代码自定义实现,不写在 yml 配置;适合全局鉴权、全局日志。
💡区别记忆:
GatewayFilter:绑定路由,哪个路由配置就哪个路由用;
GlobalFilter:全局,全部请求都经过。
1.GatewayFilter(局部过滤器)
局部过滤器GatewayFilter 使用举例AddRequestParameter
-
和 Predicate 一样,在
application.yml中配置。
-
示例:
AddRequestParameter可以给转发后的请求添加请求参数,在服务中获取过滤器的参数
-
测试

局部过滤器GatewayFilterFactory提供的一些Fitler
属于局部过滤器,写在routes下filters,只对当前这条路由生效
1. 请求Header处理
| 过滤器 | 作用 | yml示例 |
|---|---|---|
|
| 给转发后端的请求新增请求头 |
|
|
| 删除请求中的某个Header |
|
2. 请求参数处理
| 过滤器 | 作用 | yml示例 |
|---|---|---|
|
| 给转发后端的请求添加请求参数 |
|
3. 响应Header处理
| 过滤器 | 作用 | yml示例 |
|---|---|---|
|
| 给返回客户端的响应新增响应头 |
|
|
| 删除返回客户端的某个响应头 |
|
4. RequestRateLimiter 限流过滤器 ⭐
-
底层:
RedisRateLimiter,令牌桶算法,需要Redis环境
四大限流算法总结📌
示例场景:限制每分钟最多 1000 次请求
1. 固定窗口(计数器)
原理:把时间切成固定大小窗口(比如 0‑60s 为一个窗口),窗口内计数,超过阈值直接拒绝;时间到计数器清零。
缺陷:临界窗口突刺问题。
例:59s 瞬间打满 1000 请求,下一个窗口 1s 又打满 1000;1 秒内总共 2000 请求,超过限流上限。
优点:实现简单,内存占用小。
2. 滑动窗口
原理:把大窗口切分成很多小格子,窗口随时间向前滑动,淘汰已经过去的小格子,统计当前窗口总请求数。
解决:固定窗口的临界突刺问题。
缺点:实现相对复杂,需要记录每个小格子计数。
滑动窗口粒度越小,限流越精准。
3. 漏桶算法
模型:桶接收请求(生产者往桶倒水);桶底部以固定速率流出请求交给后端服务;桶满了新请求直接丢弃。
特点:输出速率恒定,强制削峰。
缺点:面对突发流量处理差。即使系统空闲,来了大量请求也只能匀速处理,没法利用空闲的系统能力。
类比:水桶,进水可以忽大忽小,出水永远匀速,水满溢出。
4. 令牌桶算法(生产项目最常用)
模型:以固定速率往桶里放令牌(例:每秒放 5 个令牌);请求过来,必须拿到令牌才允许访问;桶存令牌有最大容量,桶满就不再新增令牌。
特点:
正常情况按速率限流;
桶里积攒了多余令牌时,可以处理突发流量(短时间允许大量请求)。
对比漏桶:漏桶限制流出速率;令牌桶允许一定程度突发。
SpringCloud Gateway、Sentinel、Guava RateLimiter 底层大量使用令牌桶思想
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 #令牌填充速率,每秒允许处理请求数
redis-rate-limiter.burstCapacity: 20 #令牌桶最大容量,允许突发流量峰值
redis-rate-limiter.requestedTokens: 1 #一次请求消耗几个令牌,默认1
参数解释:
-
replenishRate:每秒往桶放多少令牌,代表稳定允许的QPS -
burstCapacity:桶最大存放令牌数量,代表最大突发峰值流量 -
requestedTokens:每一次请求消耗令牌数,大部分场景保持1
⚠️注意:使用该过滤器项目必须引入Redis依赖,网关连接Redis。
5. Retry 重试过滤器
-
作用:后端服务不可用、报错时,网关自动重试请求
filters:
- name: Retry
可以配置重试次数、哪些状态码需要触发重试。
6. RequestSize 过滤器
-
作用:限制请求包最大体积,防止大文件恶意请求打垮服务
-
单位:字节,默认上限5M
-
触发超限返回状态码:
413 Payload Too Large(请求体过大)
filters:
- name: RequestSize
args:
maxSize: 5000000
5000000字节≈5MB;做文件上传网关时,需要调大这个数值。
2. default‑filters 默认过滤器 ⭐
区别:
写在单个
routes里面的filters:局部过滤器GatewayFilter,只对当前这一条路由生效写在
spring.cloud.gateway.default-filters:默认过滤器,作用于网关所有路由,不需要给每一条路由重复写相同过滤器。
yaml结构示例:、

测试:

💡使用场景:所有接口都要统一添加请求头、统一日志,就放到default‑filters,避免每个路由重复配置。
⚠️注意:
default‑filters依然属于GatewayFilter(局部过滤器工厂),不是GlobalFilter全局过滤器。底层还是GatewayFilterFactory,只是网关自动把这套过滤器附加给每一条路由。
2.GlobalFilter(全局过滤器)
GlobalFilter是Spring Cloud Gateway中的全局过滤器,它和GatewayFilter的作⽤是相同的。
GlobalFilter,会应⽤到所有的路由请求上,全局过滤器通常⽤于实现与安全性,性能监控和⽇志记录等相关的全局功能.
使用:
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.修改application.yml文件
spring:
cloud:
gateway:
metrics:
enabled: true
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
shutdown:
enabled: true
3.测试http://127.0.0.1:10030/actuator

3.过滤器执行顺序:
每⼀个过滤器都必须指定⼀个int类型的order值,默认值为0,表⽰该过滤的优先级.order值越⼩,优先级越⾼,执⾏顺序越靠前.
Filter通过实现Order接⼝或者添加@Order注解来指定order值。
Spring Cloud Gateway提供的Filter由Spring指定。用户也可以⾃定义Filter,由用户指定。
当过滤器的order值⼀样时,会按照defaultFilter>GatewayFilter>GlobalFilter的顺序执⾏。
对比总结
| 配置位置 | 生效范围 | 类型 |
|---|---|---|
| 某条route下 filters | 仅当前这条路由 | GatewayFilter局部过滤器 |
| spring.cloud.gateway.default‑filters | 全部路由 | GatewayFilter局部过滤器(批量应用) |
| Java实现GlobalFilter接口 | 全部请求,代码编写 | GlobalFilter全局过滤器 |
default‑filters 和 GlobalFilter 有什么不一样?
default‑filters:yml配置,是内置GatewayFilter工厂批量给所有路由添加;依然属于路由过滤器链的一部分。GlobalFilter:Java代码自定义实现,优先级可以自由设置,功能更强,可以写复杂鉴权业务逻辑。
4.自定义过滤器
定义GatewayFilter
简单总结
-
类名规则:Java类
CustomGatewayFilterFactory,yml配置只写前缀name: Custom。 -
CustomConfig:接收yml里
args的参数,name: test_Custom会注入到Config的name字段。 -
apply():编写过滤器逻辑,分Pre前置(执行业务前)、Post后置(响应返回前)逻辑。 -
getOrder():设置过滤器执行优先级,数值越小优先级越高。 -
加上
@Component交给Spring管理,网关路由配置即可生效。
核心:类名去掉
GatewayFilterFactory就是yml中过滤器的name,args参数映射到Config类属性。

针对这个Filter的配置,使⽤CustomConfig定义
配置:

⾃定义GlobalFilter
GlobalFilter的实现⽐较简单,它不需要额外的配置,只需要实现GlobalFilter接⼝,⾃动会过滤所有的

测试:

更多推荐



所有评论(0)