首页/新闻资讯/正文详情

Spring Cloud:分布式系统的“粘合剂”(八)

发布时间:2026/9/26 8:51:50 来源:云帆数科 栏目:资讯中心
Spring Cloud:分布式系统的“粘合剂”(八)
专栏Spring Cloud个人主页手握风云目录一、网关介绍1.1. 引入网关要解决的问题1.2. API 网关概念1.3. 主流网关产品二、Spring Cloud Gateway 核心使用2.1. 搭建网关服务2.2. 路由断言工厂2.3. 网关过滤器工厂2.4. 自定义过滤器一、网关介绍1.1. 引入网关要解决的问题在微服务技术体系中我们已经借助 Eureka、Nacos 实现服务的注册与发现依靠 Spring Cloud LoadBalancer 完成负载均衡通过 OpenFeign 实现服务之间的远程调用。但此时会暴露出一个现实问题所有微服务接口直接对外暴露外部客户端可以直接访问各个微服务。为保障接口访问安全业务系统需要增加权限校验逻辑。而微服务架构把原本单体应用拆分成了多个独立服务就会造成权限校验代码在每一个微服务中重复编写。一旦校验规则发生改动开发人员就需要修改、更新多个服务大大增加维护成本。针对该痛点行业普遍的解决方案就是引入 API 网关。我们可以用公司办公的场景来形象理解网关的价值。单体架构好比公司只有一名员工来访人员直接由这名员工完成身份核验并处理业务。演进到微服务架构后公司划分出多个独立部门每个部门都要自行对来访者做身份核实。这种模式不仅办事效率低下还加重各个部门人员的工作负担。为了解决该问题公司设立统一的前台岗位全部来访人员先由前台完成身份校验校验通过之后内部各个部门就直接信任来访者处理对应的业务。这里的前台就等价于微服务体系中的 API 网关。1.2. API 网关概念API 网关本身也是一个独立服务它是后端全部微服务的唯一对外入口设计思想对应门面Facade设计模式。网关充当整个微服务集群的门面角色外部客户端发起的所有请求都必须经过网关完成调度与过滤网关自身不实现具体业务逻辑。网关四大核心功能权限控制校验用户身份非法请求直接拦截。动态路由按照配置规则把请求转发给对应的后端微服务。负载均衡目标服务存在多个实例时分发请求。限流限制请求流量保护下游微服务防止被大流量压垮。1.3. 主流网关产品市面上存在多款成熟的开源网关产品包括 Nginx、Kong、Zuul 以及 Spring Cloud Gateway。其中 Zuul 是 Netflix 开源的网关组件可以和 Eureka、Ribbon、Hystrix 等组件协同工作在 Spring Cloud Finchley 版本之前是官方推荐网关。但 Netflix 在 2018 年宣布 Zuul 进入维护状态不再迭代新增功能。Spring Cloud Gateway 是 Spring 官方推出的全新网关组件基于 Spring、Spring Boot 开发设计目标就是用来替代 Zuul。它可以为微服务提供请求转发能力同时处理安全校验、监控统计、服务弹性这类横切业务。官方性能测试数据显示Spring Cloud Gateway 每秒处理请求数 RPS达到 Zuul1.X 版本的 1.6 倍性能表现更加优异。二、Spring Cloud Gateway 核心使用2.1. 搭建网关服务创建 gateway Maven 模块引入 3 个核心依赖dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-gateway/artifactId /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-loadbalancer/artifactId /dependency编写启动类package com.yang.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); } }application.yml 路由配置server: port: 10030 spring: application: name: gateway cloud: nacos: discovery: server-addr: 154.8.196.189:8848 gateway: metrics: enabled: true routes: - id: order-service # 路由唯一标识自定义 uri: lb://order-service/ # 目标服务地址lb://服务名代表从 Nacos 注册中心获取服务lb loadbalance 开启负载均衡 predicates: # 路由断言匹配请求条件匹配成功才转发 - Path/order/** - id: product-service uri: lb://product-service/ predicates: - Path/product/**测试接口http://127.0.0.1:10030/order/12.2. 路由断言工厂Predicate 是 Java 8 提供的函数式编程接口接收一个参数返回布尔类型结果主要用于条件过滤与请求参数校验。它定义了 test 抽象方法除此之外还提供 isEqual、and、or、negate 等默认方法可以实现对象相等判断、逻辑与、逻辑或、逻辑取反等操作。在代码编写的时候除了直接定义实现类之外还可以使用匿名内部类、Lambda 表达式、方法引用等多种方式来完成 Predicate 对象的创建。package predicate; import java.util.function.Predicate; public class StringPredicate implements PredicateString { Override public boolean test(String s) { return s null || s.isEmpty(); } }package predicate; import org.junit.Test; import java.util.function.Predicate; public class PredicateTest { Test public void test1() { PredicateString predicate new StringPredicate(); System.out.println(predicate.test()); System.out.println(predicate.test(hello)); } Test public void test2() { PredicateString predicate new PredicateString() { Override public boolean test(String s) { return s null || s.isEmpty(); } }; System.out.println(predicate.test()); System.out.println(predicate.test(hello)); } Test public void test3() { PredicateString predicate s - s null || s.isEmpty(); System.out.println(predicate.test()); System.out.println(predicate.test(hello)); } Test public void test4() { // 创建一个PredicateString对象判断字符串是否为null或空 PredicateString predicate s - s null || s.isEmpty(); // 打印negate()方法对空字符串的测试结果应为true System.out.println(predicate.negate().test()); // 打印negate()方法对非空字符串hello的测试结果应为true System.out.println(predicate.negate().test(hello)); } Test public void test5() { // 判断字符串是否等于aa PredicateString predicate1 s - aa.equals(s); // 判断字符串是否等于bb PredicateString predicate2 s - bb.equals(s); // predicate1 和 predicate2 都为 false所以 or 结果为false System.out.println(predicate1.or(predicate2).test()); // predicate1为true所以or结果为true System.out.println(predicate1.or(predicate2).test(aa)); } Test public void test6() { // 定义第一个Predicate判断字符串是否不为空且长度大于0 PredicateString predicate s - s ! null !s.isEmpty(); // 定义第二个Predicate判断字符串是否不为空且所有字符都是数字 PredicateString predicate2 s - s ! null s.chars().allMatch(Character::isDigit); System.out.println(predicate.and(predicate2).test(aa)); System.out.println(predicate.and(predicate2).test(123)); } }在 Spring Cloud Gateway 当中路由断言工厂 Route Predicate Factories 负责提供路由规则的匹配能力。我们在配置文件中书写的断言规则仅仅是字符串这些字符串会被对应的路由断言工厂读取解析最终转换成用于路由判断的条件逻辑。例如前面案例中用到的 Path/product/** 路径匹配规则底层就是由 PathRoutePredicateFactory 来实现解析。网关内置了大量不同的路由断言工厂分别可以针对 HTTP 请求的时间、Cookie、请求头、域名、请求方式、访问路径、客户端 IP 等各类属性进行匹配多条断言规则之间默认按照逻辑与and的关系进行组合只有全部条件满足当前路由才会生效。断言功能After / Before / Between按照时间匹配请求Cookie匹配 Cookie 键 正则表达式Header匹配请求头 key 与正则Host匹配请求 Host 域名Method匹配 HTTP 请求方式 GET/POST 等Path最常用匹配请求 URL 路径支持通配符/**RemoteAddr匹配客户端 IP 网段我们可以通过配置文件完成断言规则的添加与测试。比如给路由增加 After 时间断言限定只有指定时间之后发起的请求才能够被路由转发。如果客户端发起请求的时间不满足断言条件网关就不会匹配该路由访问接口时就会返回 404调整配置当中的时间参数让当前时间满足断言条件之后接口就可以正常访问请求会按照配置转发到对应的后端微服务。2.3. 网关过滤器工厂路由断言Predicate的作用是判定当前请求应该交由哪一条路由进行处理而如果需要在请求流转的前后追加自定义处理逻辑就需要依靠过滤器Filter来实现。过滤器按照执行时机可以划分为 Pre 前置过滤器和 Post 后置过滤器两大类Pre 类型过滤器会在请求转发到后端微服务之前执行鉴权、限流这类操作都适合放在这一阶段完成。Post 类型过滤器则是在后端服务处理完毕结果返回给客户端之前执行。我们可以用景区游玩的场景简单理解这个过程进入景区前的安检、验票、人流管控对应Pre过滤器游玩结束之后的评价操作对应Post过滤器过滤器属于可选组件并不是必须配置。Spring Cloud Gateway内置了大量过滤器用来对 Web 请求做拦截与链式处理可以实现权限校验、访问超时设置等多种功能。从作用范围上区分过滤器又分为GatewayFilter和GlobalFilter两种GatewayFilter作用于单个路由或者一组路由GlobalFilter 则会对项目中全部路由生效覆盖所有客户端请求。GatewayFilter 属于局部过滤器和路由断言 Predicate 一样大多在application.yml配置文件当中完成配置每一个过滤器都封装好了固定逻辑。比如AddRequestParameterGatewayFilterFactory我们只需要在配置中写上对应的过滤器名称就能够自动为请求添加参数。在实际使用时如果直接写在某一个路由的filters配置块下该过滤器就只会对当前这条路由生效。我们可以通过简单案例演示它的效果在product‑service路由下配置AddRequestParameter 过滤器为请求添加固定参数随后在下游product‑service服务的接口中接收并打印该参数重启网关与业务服务后发起调用就能够在业务服务控制台观察到网关传递过来的参数。spring: gateway: metrics: enabled: true routes: filters: - AddRequestParameteruserName, yangRequestMapping(/o1) public String o1(Integer id, String userName) { log.info(接收到过滤器添加的参数, userName:{}, userName); return productApi.p1(id); }测试接口http://127.0.0.1:10030/feign/o1?id1http://127.0.0.1:8080/users/user-id-here/permissionsSpring Cloud Gateway 提供了十分丰富的内置 GatewayFilter 工厂。常见内置 GatewayFilterAddRequestHeader / AddRequestParameter添加请求头、请求参数AddResponseHeader添加响应头RemoveRequestHeader / RemoveResponseHeader删除请求 / 响应头RequestRateLimiter限流Redis 令牌桶算法超限返回 429Retry后端异常自动重试RequestSize限制请求体大小超限返回 413。如果希望过滤器对所有路由都生效不需要在每一个路由下重复配置可以使用 default‑filters 默认过滤器配置写在 gateway 顶层节点下对全部路由统一生效。GlobalFilter 是网关的全局过滤器它和 GatewayFilter 的处理能力一致区别在于会作用于全部路由常常用来实现全局安全校验、性能监控、日志记录这类全局性业务。网关本身自带不少内置全局过滤器例如采集网关运行指标的 Gateway Metrics Filter、实现本地请求转发的 Forward Routing Filter、为下游服务做负载均衡的 LoadBalancer Client Filter。想要使用监控相关的全局过滤器需要引入actuator监控依赖在配置文件中开启网关 metrics 指标并且暴露对应的监控端点访问actuator地址就可以查看网关各类监控信息。引入依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency添加配置spring: gateway: metrics: enabled: true management: endpoints: web: exposure: include: * endpoint: health: enabled: true过滤器执行顺序规则每个过滤器有 order 整型值order 数值越小优先级越高执行越靠前可以通过Ordered接口或者Order注解设置。order 值相同时执行顺序default‑filters GatewayFilter GlobalFilter。网关会把所有过滤器合并为一条过滤器链排序后依次执行。2.4. 自定义过滤器Spring Cloud Gateway 提供了灵活的过滤器扩展能力开发者可以结合实际业务场景自定义过滤器逻辑自定义过滤器同样支持 GatewayFilter 和 GlobalFilter 两种类型分别适配局部路由生效和全局路由生效两种使用场景。自定义 GatewayFilter 需要实现 GatewayFilterFactory 接口Spring Boot 默认提供了 AbstractGatewayFilterFactory 抽象类开发者可以直接继承该抽象类简化开发。自定义类需要以 GatewayFilterFactory 作为类名后缀这是因为网关默认会取类名的前缀作为配置文件中引用的过滤器名称同时类需要添加 Service 注解交由 Spring 容器进行管理。除此之外还需要在类内部定义一个配置类用来接收 yml 配置文件中传入的参数。在重写的 apply 方法中可以完整实现过滤器的前置与后置处理逻辑。其中调用 chain.filter (exchange) 之前的代码属于 Pre 阶段会在请求转发到下游微服务之前执行通过 then 方法调用 Mono.fromRunnable 包裹的代码属于 Post 阶段会在下游服务处理完成、响应返回给客户端之前执行。方法中涉及的 ServerWebExchange 是 HTTP 请求与响应的交互契约封装了请求、响应的完整上下文信息GatewayFilterChain 则代表过滤器链用于驱动请求在过滤器之间流转。开发者还可以通过重写 getOrder 方法指定过滤器的优先级order 数值越大优先级越低执行顺序越靠后。完成代码开发后需要在 application.yml 的对应路由下配置该过滤器。配置时通过 name 指定过滤器的名称前缀通过 args 传入配置类对应的参数配置完成后该过滤器仅对当前路由生效。重启网关与下游业务服务访问对应接口观察控制台日志就可以看到 Pre 和 Post 阶段依次输出的日志信息验证自定义过滤器的执行效果。package com.yang.gateway; import lombok.Data; Data public class CustomConfig { private String name; }package com.yang.gateway; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; Component public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactoryCustomConfig implements Ordered { private static final Logger log LoggerFactory.getLogger(CustomGatewayFilterFactory.class); /** * ServerWebExchange: HTTP 请求-响应交互契约, 提供了对HTTP请求和响应的访问 * GatewayFilterChain: 过滤器链 * Mono: Reactor的核心类, 数据流发布者,Mono最多只能触发一个事件.可以把Mono用在异步完成任务时,发出通知 * chain.filter(exchange) 执行请求 * Mono.fromRunnable() 创建一个包含Runnable元素的数据流 */ public CustomGatewayFilterFactory() { super(CustomConfig.class); } Override public GatewayFilter apply(CustomConfig config) { return new GatewayFilter() { Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info(Pre Filter, config:{} , config); return chain.filter(exchange).then(Mono.fromRunnable(() - { log.info(Post Filter...); })); } }; } Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } }spring: gateway: routes: filters: - AddRequestParameteruserName, yang - name: Custom args: name: test_custom自定义 GlobalFilter 的实现方式更为简洁它不需要额外定义配置类也无需在每个路由下单独配置。开发者只需要实现 GlobalFilter 接口与 Ordered 接口为类添加 Service 注解该过滤器就会自动应用到项目中的所有路由上适合用来实现全局鉴权、全链路日志、统一监控这类全局性的横切逻辑。自定义 GlobalFilter 的核心逻辑同样写在 filter 方法中和 GatewayFilter 一样通过 chain.filter (exchange) 划分前置处理与后置处理两个阶段结合 Mono.fromRunnable 完成后置逻辑的编写。重写 getOrder 方法可以调整全局过滤器在整个过滤器链中的执行顺序灵活控制不同过滤器的执行先后。重启网关服务后访问业务接口观察日志输出可以验证过滤器的执行顺序。当自定义 GatewayFilter 与自定义 GlobalFilter 的 order 值相同时前置阶段会先执行 GatewayFilter 的逻辑再执行 GlobalFilter 的逻辑后置阶段则顺序相反先执行 GlobalFilter 的后置逻辑再执行 GatewayFilter 的后置逻辑整体呈现出先进后出的过滤器链执行特征。package com.yang.gateway; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; Slf4j Component public class CustomGlobalFilter implements GlobalFilter, Ordered { Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info(Pre Global Filter); return chain.filter(exchange).then(Mono.fromRunnable(() - { log.info(Post Global Filter); })); } Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } }

相关推荐

Atlas 300V 24G推理卡部署YOLO实战:从PyTorch到OM全流程
Atlas 300V 24G推理卡部署YOLO实战:从PyTorch到OM全流程

1. 先说清楚:Atlas 300V 24G 到底是什么卡1.1 一张卡解决什么问题我第一块 Atlas 300V 24G 上架的时候,身边同事问的第一句话就是:“这是运算加速卡吗?”答案是肯定的,它的完整定位是昇腾推理加速卡,不是用… · 2026/9/26 8:51:50

零LLM合规引擎:确定性规则与CI拦截的工程实践
零LLM合规引擎:确定性规则与CI拦截的工程实践

1. 为什么我们给合规引擎上了"零LLM"的紧箍咒第一次听到"合规引擎里一行LLM调用都没有"这个说法,很多同行的第一反应是:都什么年代了,还不用大模型?但如果你真的做过欧盟AI法案(EU AI Act&#xf… · 2026/9/26 8:51:44

Atlas 300V推理加速卡实战:从环境配置到YOLO模型部署全解析
Atlas 300V推理加速卡实战:从环境配置到YOLO模型部署全解析

先把结论放到最前面:Atlas 300V系列毫无疑问是运算加速卡,但它的"加速"和大多数人熟悉的GPU加速完全是两码事。我见过不少朋友把这张卡买回来,插上服务器,装好驱动,然后对着npu-smi里那一串输出发呆——接下… · 2026/9/26 8:51:38

最近爆火的Manus横空出世,到底是什么?TaoToken统一Key接入AI智能体实战解析
最近爆火的Manus横空出世,到底是什么?TaoToken统一Key接入AI智能体实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 10:13:58

反刍 AI-MUD-MCP 游戏开发日志:用 FastMCP 搭代码框架,TaoToken 统一 Key 接入 DeepSeek
反刍 AI-MUD-MCP 游戏开发日志:用 FastMCP 搭代码框架,TaoToken 统一 Key 接入 DeepSeek

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 10:13:58

教会 AI 智能体相互对话 — OpenClaw 中的智能体间通信与 TaoToken 配置
教会 AI 智能体相互对话 — OpenClaw 中的智能体间通信与 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 10:13:52

GraphQL 客户端实战指南:Apollo Client 与 Relay 的缓存、校验与数据协同定位
GraphQL 客户端实战指南:Apollo Client 与 Relay 的缓存、校验与数据协同定位

【免费下载链接】howtographql The Fullstack Tutorial for GraphQL 项目地址: https://gitcode.com/gh_mirrors/ho/howtographql 点击查看 免费下载 在 GraphQL 全栈架构中,客户端承担着将声明式查询转化为网络请求、管理本地缓存、驱动 UI 更新等关键… · 2026/9/26 10:13:52

AI创作工作台搭建指南:Prompt、Skill与知识库的工程化实践
AI创作工作台搭建指南:Prompt、Skill与知识库的工程化实践

1. 这套工作台到底解决了什么问题先说说我自己的经历。去年有段时间我同时在跑三个项目:一个技术博客的选题库、一个短视频脚本流水线、还有一个给客户做的行业知识库。每个项目单独看都不复杂,但凑在一起就变成了灾难——提示词散落在备忘录、飞书文档、… · 2026/9/26 10:13:39

RS485与LoRa联合调试工具:参数空间导航与收敛式验证
RS485与LoRa联合调试工具:参数空间导航与收敛式验证

1. 这个工具到底在解决什么真实痛点?Workbuddy自动写一个RS485 / LoRa参数调试工具——光看标题,很多人第一反应是:“又一个串口调试助手?”但如果你真在工业现场、农业物联网或智能楼宇项目里摸爬滚打过,就会立刻意识… · 2026/9/26 10:13:33

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码