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 二次开发而来:

  1. 原生 Feign:Netflix 开源,只实现声明式调用,不自带负载均衡;
  2. 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 客户端接口(声明式远程接口)

注解说明:

  1. @FeignClient(value = "product-service")

    • value:被调用服务的服务名称(Nacos/Eureka 注册的服务名),Feign 结合负载均衡自动完成服务发现。

  2. path = "/product":目标服务所有接口的公共前缀,等价于 Controller 上的 @RequestMapping("/product")。

  3. 接口内的方法写法、注解、入参规则必须和被调用服务的 Controller 完全一致。

4.OpenFeign参数传递

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

2.在ProductApi编写客户端接口

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


5.OpenFein最佳实践

最佳实践1

一、解决的痛点

常规写法里:, Feign的客⼾端与服务提供者的controller代码⾮常相似, Feign的客⼾端与服务提供者的controller代码⾮常相似,服务提供者 Controller、消费者 Feign 接口 两份代码要手写一模一样的接口签名,路径、注解、参数极易写错、维护繁琐。 Feign 继承方案统一抽取公共接口,两端复用,消除重复代码。

二、整体架构(对应你新建的 product-api 模块)

  1. 公共模块 product-api(打成公共 jar) 存放标准父接口 ProductApi,定义全部接口签名、请求注解(@GetMapping、@PathVariable 等),将打好的 jar 安装到本机 Maven 本地仓库;

  2. 服务提供者 product-service Controller 实现 product-api 里的公共接口,只写业务逻辑即可,不用重复写接口注解与路径。

  3. 服务消费者 order-service Feign 客户端接口 继承 product-api 里的公共接口,仅添加 @FeignClient 注解。

最佳实践2

Feign 抽取⽅式

1.建公共模块 product-api,将ProductApi和ProductInfo移入,打成公共 jar

2.OrderController类

3.OderService 类

4.测试

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

网关

  1. 已有技术现状:Eureka/Nacos 实现服务注册发现、SpringCloud LoadBalance 完成负载均衡、OpenFeign 实现远程调用。
  2. 现存痛点:微服务各个接口直接对外开放,每个微服务都要单独实现权限校验逻辑;一旦校验规则变更,需要修改所有服务,维护繁琐。
  3. 通俗类比:
    • 单体架构:单人处理身份核验 + 业务办理;
    • 微服务架构:多个部门各自都要核验身份,效率低、流程冗余;
  4. 解决方案:引入API 网关充当统一前台,由网关统一完成身份、权限校验,校验放行后内部微服务无需重复校验,解决重复鉴权、维护麻烦的问题。

网关四大核心功能简述

1. 权限控制

网关作为整个微服务集群的统一入口,集中完成身份、权限校验;校验失败直接拦截请求,校验通过才放行,以此避免每个微服务重复编写鉴权逻辑。

2. 动态路由

所有外部请求统一抵达网关,网关本身不处理业务逻辑,按照预设规则将请求转发至对应的后端微服务。

3. 负载均衡

若目标微服务部署了多个实例,网关会自动进行负载分发,将请求分配给不同实例,实现流量均分。

4. 限流

当接口访问流量突增时,网关依照配置的流量阈值放行请求,超额流量直接拦截,防止后端服务因流量冲击崩溃。

常见网关方案简述

业界主流开源网关包含 Nginx、Kong、Zuul、Spring Cloud Gateway 等,课程重点对比 Zuul 与 Spring Cloud Gateway:

一、Zuul

  1. 归属:Netflix 开源网关组件,属于 Spring Cloud Netflix 体系,可搭配 Eureka、Ribbon、Hystrix 协同工作。
  2. 历史地位:Spring Cloud Finchley 版本之前,是官方推荐网关方案。
  3. 现状:Netflix 在 2018 年停止为 Zuul 迭代新功能,仅做基础维护,现已逐步被替代。

二、Spring Cloud Gateway

  1. 定位:Spring Cloud 官方推出的全新网关,基于 Spring + SpringBoot 开发,设计初衷就是用来替代 Zuul。
  2. 能力:负责请求转发,同时统一提供安全校验、监控、容错等高可用横切能力。
  3. 性能优势:官方压测数据显示,其每秒处理请求数(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)短路或 `
任意一个条件成立就为 true,短路特性:第一个条件 true,后面不再执行
`
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示例

AddRequestHeader

给转发后端的请求新增请求头

- AddRequestHeader=X-Request-red, blue

RemoveRequestHeader

删除请求中的某个Header

- RemoveRequestHeader=X-Request-Foo

2. 请求参数处理

过滤器

作用

yml示例

AddRequestParameter

给转发后端的请求添加请求参数

- AddRequestParameter=red,blue

3. 响应Header处理

过滤器

作用

yml示例

AddResponseHeader

给返回客户端的响应新增响应头

- AddResponseHeader=X-Response-Red,Blue

RemoveResponseHeader

删除返回客户端的某个响应头

- RemoveResponseHeader=X-Response-Foo


4. RequestRateLimiter 限流过滤器 ⭐

  • 底层:RedisRateLimiter,令牌桶算法,需要Redis环境

四大限流算法总结📌

示例场景:限制每分钟最多 1000 次请求

1. 固定窗口(计数器)

  • 原理:把时间切成固定大小窗口(比如 0‑60s 为一个窗口),窗口内计数,超过阈值直接拒绝;时间到计数器清零。

  • 缺陷:临界窗口突刺问题。

例:59s 瞬间打满 1000 请求,下一个窗口 1s 又打满 1000;1 秒内总共 2000 请求,超过限流上限。

  • 优点:实现简单,内存占用小。


2. 滑动窗口

  • 原理:把大窗口切分成很多小格子,窗口随时间向前滑动,淘汰已经过去的小格子,统计当前窗口总请求数。

  • 解决:固定窗口的临界突刺问题。

  • 缺点:实现相对复杂,需要记录每个小格子计数。

滑动窗口粒度越小,限流越精准。


3. 漏桶算法

  • 模型:桶接收请求(生产者往桶倒水);桶底部以固定速率流出请求交给后端服务;桶满了新请求直接丢弃。

  • 特点:输出速率恒定,强制削峰。

  • 缺点:面对突发流量处理差。即使系统空闲,来了大量请求也只能匀速处理,没法利用空闲的系统能力。

类比:水桶,进水可以忽大忽小,出水永远匀速,水满溢出。


4. 令牌桶算法(生产项目最常用)

  • 模型:以固定速率往桶里放令牌(例:每秒放 5 个令牌);请求过来,必须拿到令牌才允许访问;桶存令牌有最大容量,桶满就不再新增令牌。

  • 特点:

    1. 正常情况按速率限流;

    2. 桶里积攒了多余令牌时,可以处理突发流量(短时间允许大量请求)。

  • 对比漏桶:漏桶限制流出速率;令牌桶允许一定程度突发。

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

参数解释:

  1. replenishRate:每秒往桶放多少令牌,代表稳定允许的QPS

  2. burstCapacity:桶最大存放令牌数量,代表最大突发峰值流量

  3. 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 有什么不一样?

  1. default‑filters:yml配置,是内置GatewayFilter工厂批量给所有路由添加;依然属于路由过滤器链的一部分。
  2. GlobalFilter:Java代码自定义实现,优先级可以自由设置,功能更强,可以写复杂鉴权业务逻辑。

4.自定义过滤器

 定义GatewayFilter

简单总结

  1. 类名规则:Java类CustomGatewayFilterFactory,yml配置只写前缀name: Custom。

  2. CustomConfig:接收yml里args的参数,name: test_Custom会注入到Config的name字段。

  3. apply():编写过滤器逻辑,分Pre前置(执行业务前)、Post后置(响应返回前)逻辑。

  4. getOrder():设置过滤器执行优先级,数值越小优先级越高。

  5. 加上@Component交给Spring管理,网关路由配置即可生效。

核心:类名去掉GatewayFilterFactory就是yml中过滤器的name,args参数映射到Config类属性。

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

配置:

⾃定义GlobalFilter

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

测试:

    更多推荐