网关 + Nacos配置管理
网关
网关:就是网络的关口,负责请求的路由、转发、身份校验。

网关路由
- 新建网关模块gateway
- 引入相关依赖
<!--网关-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos discovery-->
<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>
- 写启动类
- 配置路由规则
server:port: 8080 # 前端请求的端口(网关的端口)spring:application:name: gateway # 服务名称cloud:nacos:server-addr: 192.168.140.101:8848 # nacos地址# 路由配置gateway:routes:- id: item-service # 路由规则id,自定义,唯一uri: lb://item-service # 路由目标微服务,lb代表负载均衡协议predicates: # 路由断言,判断请求是否符合要求,符合则路由到目标- Path=/items/**, /search/** # 以请求路径做判断,以/items或/search开头则符合- id: user-serviceuri: lb://user-servicepredicates:- Path=/addresses/**, /users/**- id: trade-serviceuri: lb://trade-servicepredicates:- Path=/orders/**- id: pay-serviceuri: lb://pay-servicepredicates:- Path=/pay-orders/**- id: cart-serviceuri: lb://cart-servicepredicates:- Path=/carts/**
路由属性
网关路由对应的Java类型是RouteDefinition,常见的属性有:
- id:路由唯一标识
- uri:路由目标地址
- predicates:路由断言,判断请求是否符合当前路由
- filters:路由过滤器,对请求或响应做特殊处理
predicates路由断言
文档:predicates路由断言

filters路由过滤器
文档:filters路由过滤器

自定义过滤器
网关过滤器有两种:
- GatewayFilter:路由过滤器,作用于任意指定的路由,默认不生效,要陪知道路由后生效。
- GlobalFilter(常用):全局过滤器,作用范围是所有路由;声明后自动生效。

自定义GlobalFilter
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取请求HttpHeaders headers = exchange.getRequest().getHeaders();// 过滤器业务处理(登录校验逻辑...)if(...) {// 拦截ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}return chain.filter(exchange); // 放行}// 控制过滤器执行顺序@Overridepublic int getOrder() {return 0; // 值越小,优先级越高}
}
自定义的过滤器需要在NettyRoutingFilter【将请求转发到微服务】这个过滤器之前执行,所以需要再继承一个Ordered接口,来保证我们自定义的过滤器的优先级比NettyRoutingFilter高
网关登录校验

网关传递用户

- 在网关的登录校验过滤器中,从前端发送的请求头里拿到用户信息,并把用户信息放到请求头里,再发给微服务。
ServerWebExchange swe = exchange.mutate().request(builder -> builder.header("user-info", userInfo)).build(); // 传递的时候,需要传递这个返回的新的exchange
- 在微服务中定义拦截器,保存网关发过来的用户信息到ThreadLocal里。
// 定义拦截器
// 因为校验请求头这些操作已经在网关做过了,所以拦截器里边只需要把用户信息保存到ThreadLocal里即可
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 获取用户信息String userInfo = request.getHeader("user-info");// 判断是否获取了用户信息if(StrUtil.isNotBlank(userInfo)) {// 存入上下文UserContext.setUser(Long.valueOf(userInfo));}// 放行return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 清理用户UserContext.removeUser();}
}
// 注册拦截器
/*** DispatcherServlet.class:springmvc的核心api* 防止网关【没有SpringMvc】也引用这个类*/
@ConditionalOnClass(DispatcherServlet.class) // 条件注解
@Configuration
public class MvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor());}
}
由于很多微服务,都需要获取用户信息,不可能在这么多微服务里都一个拦截器,太麻烦啦。所以就把拦截器的代码写在common公共模块。
【问题】:配置类想要生效,需要被Spring扫描包扫描到,但是现在mvc配置类是在common公共模块下,但是是其他微服务使用这个拦截器,无法扫描到这个配置类。
【解决】:利用SpringBoot自动装配的原理,将定义的配置类放在了META-INF下的spring.factories文件下,这样就能实现自动装
OpenFeign传递用户信息

【分析】:购物车服务中的请求,不是直接从网关发过来的,而是网关先发给交易服务,再由交易服务通过OpenFeign向购物车服务中发送请求【微服务之间的调用】。
【解决】:OpenFeign提供了一个拦截器接口,所有由OpenFeign发起的请求都会先调用拦截器处理请求。
public class DefaultFeignConfig {@Beanpublic RequestInterceptor userInfoRequestInterceptor() {return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate template) {// 交易服务可以拿到用户信息,它向购物车发请求时,UserContext里会保存用户信息Long userId = UserContext.getUser();if (userId != null) {// 把用户信息放到请求头中template.header("user-info", userId.toString()); }}};}
}
Nacos配置管理
【存在问题】:
- 微服务重复配置过多,维护成本高。
- 业务配置经常变动,每次修改都要重启服务
- 网关路由配置写死,如果变更都要重启网关

配置共享
1. 添加共享配置
打开nacos控制台,添加一些共享配置到nacos中,包括:jdbc、日志、swagger、openfeign等配置。

2. 拉取共享配置
基于NacosConfig拉取共享配置代替微服务的本地配置

- 引入依赖
<!--nacos配置管理--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--读取bootstrap文件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency>
2.新建bootstrap.yaml文件
spring:application:name: cart-service # 微服务的名称profiles:active: devcloud:nacos:server-addr: 192.168.140.101:8848config:file-extension: yamlshared-configs:- data-id: shared-jdbc.yaml- data-id: shared-log.yaml- data-id: shared-swagger.yaml

先加载bootstrap配置文件,拉取nacos配置,再进行合并。
配置热更新
当修改配置文件中的配置时,微服务无需重启即可使配置生效。
【条件】:
- nacos中要有一个与微服务名有关的配置文件。

- 微服务中要以特定方式读取需要热更新的配置属性。
@Data
@Component
@ConfigurationProperties(prefix = "hm.cart")
public class CartProperties {private Integer maxItems;
}
对应nacos中的配置:
动态路由
要实现动态路由首先要将路由配置保存到nacos中,当nacos中路由配置变更时,推送最新配置到网关,更新网关中的路由信息。
- 拉取配置并添加监听器
- 在
路由表里的内容变更和项目启动时,更新路由表
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {private final NacosConfigManager nacosConfigManager;private final RouteDefinitionWriter writer;private final String dataId = "gateway-routes.json";private final String group = "DEFAULT_GROUP";private final Set<String> routeIds = new HashSet<>(); // 保存旧的路由表@PostConstruct // 在项目一启动的时候执行public void init() throws NacosException {// 1. 项目启动,先拉取配置,并添加配置监听器String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {@Overridepublic Executor getExecutor() { // 定义线程池return null;}@Overridepublic void receiveConfigInfo(String configInfo) { // 配置变更时做的事// 2. 监听到配置变更时,需要去更新路由表updateConfigInfo(configInfo);}});// 3. 第一次读取到配置,也需要更新路由表updateConfigInfo(configInfo);}// 更新路由表【利用RouteDefinitionWriter来更新路由表】public void updateConfigInfo(String configInfo) { // configInfo就是配置文件的内容// 1. 解析配置文件,转为RouteDefinitionList<RouteDefinition> routes = JSONUtil.toList(configInfo, RouteDefinition.class);// 2. 更新路由表// 【删】删除旧的路由表for (String routeId : routeIds) {writer.delete(Mono.just(routeId)).subscribe();}// 清空旧的路由表routeIds.clear();for (RouteDefinition route : routes) {// 【增】新增新的路由表writer.save(Mono.just(route)).subscribe();// 记录路由id,便于下次更新时删除routeIds.add(route.getId());}}
}
- 在nacos中添加动态路由

【注】:为了方便解析从nacos读取到的路由配置,推荐使用json格式的路由配置。
相关文章:
网关 + Nacos配置管理
网关 网关:就是网络的关口,负责请求的路由、转发、身份校验。 网关路由 新建网关模块gateway引入相关依赖 <!--网关--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter…...
《Spring Framework实战》6:核心技术 4.1.IoC 容器
欢迎观看《Spring Framework实战》视频教程 本章介绍 Spring 的控制反转 (IoC) 容器。 本部分摘要 Spring IoC 容器和 Bean 简介 容器概述 Bean 概述 依赖 Bean 作用域 自定义 Bean 的性质 Bean 定义继承 容器扩展点 基于注解的容器配置 Clas…...
ModuleNotFoundError: No module named ‘audioop‘
问题 ModuleNotFoundError: No module named pyaudioop ModuleNotFoundError: No module named audioop解决方案 安装库 pip3 install audioop-lts...
STM32-笔记38-I2C-oled实验
一、什么是I2C? I2C总线,全称Inter-Integrated Circuit(互连集成电路),是一种由Philips(现NXP半导体)公司在1980年代初开发的同步 串行 半双工通信总线。 二、有了串口通信为什么要使用I2C&…...
人大金仓实现主键自增.
使用数据库中自带的参数类型 serial 类型(相当于创建一个INT列), 或者bigserial(相当于创建一个BIGINT列. 示例sql: CREATE TABLE ord(id SERIAL,ord_no INT NOT NULL,ord_name VARCHAR(32),CONSTRAINT "ord_PKEY" PRIMARY KEY ("id"));插入时指定自增值…...
h264之多视点mvc编码及解码过程(JMVC平台举例)
h264标准参考平台JMVC是针对MVC标准的,JMVC支持多视点编码、合流、多视点解码操作。可以利用JMVC生成h264 mvc码流和解码。 JMVC的下载地址是:jvet / JMVC GitLabH.264/AVC multi-view coding (MVC) extension JMVC reference softwarehttps://vcgit.hh…...
小程序学习08—— 系统参数获取和navBar组件样式动态设置
一 系统信息的概念 uni-app提供了异步(uni.getSystemInfo)和同步(uni.getSystemInfoSync)的2个API获取系统信息。 success 返回参数说明: 参数分类说明statusBarHeight手机状态栏的高度system操作系统名称及版本。。。 二 自定义navbar 2.1 获取系统参数 代码展示…...
数据库环境安装(day1)
网址:MySQL 下载(环境准备): (2-5点击此处,然后选择合适的版本) 1.linux在线YUM仓库 下载/安装: wget https://repo.mysql.com//mysql84-community-release-el9-1.noarch.rpm rpm -i https://r…...
网络安全-web渗透环境搭建-BWAPP(基础篇)
01--所需系统环境: 虚拟主机系统部署(vmware,虚拟主机创建、虚拟主机网络配置(桥接,便于网络中多个主机都能访问虚拟主机)、虚拟软件功能,快照、克隆、镜像文件加载,ova文件制作&am…...
当算法遇到线性代数(三):实对称矩阵
实对称矩阵的理论与应用 线性代数系列相关文章(置顶) 1.当算法遇到线性代数(一):二次型和矩阵正定的意义 2.当算法遇到线性代数(二):矩阵特征值的意义 3.当算法遇到线性代数&#x…...
WayLand的架构和协议
WayLand的架构和协议 1. Wayland简介 1.1 Wayland是啥?为啥它这么重要? 嘿,你知道吗?有时候咱们用电脑的时候,是不是觉得图形界面有点慢、有点卡?那是因为我们还在用一个叫X Window System (X11)的老伙计…...
STM32学习(十)
I2C模块内部结构 I2C(Inter-Integrated Circuit)模块是一种由Philips公司开发的二线式串行总线协议,用于短距离通信,允许多个设备共享相同的总线。 硬件连接简单:I2C通信仅需要两条总线,即SCL&…...
进阶篇-Day17:JAVA的日志、枚举、类加载器、反射等介绍】
目录 1、日志1.1 日志概念1.2 日志框架(1) Logback框架:(2)配置文件介绍: 2、枚举3、类加载器3.1 类加载器的介绍3.2 类加载器的加载过程:加载、链接、初始化3.3 类加载器的分类3.4 双亲委派模式…...
Java设计模式 —— 【行为型模式】责任链模式(Chain-of-responsibility Pattern) 详解
文章目录 模式介绍优缺点适用场景模式结构案例实现 模式介绍 责任链模式又名职责链模式,它是一种对象行为的设计模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链&…...
C++和Python中负数取余结果的区别
C中的负数取余规则(取模%)规则 在C中,取余运算( % )的结果符号与被除数相同。从数学定义角度看,C遵循的是尽量让商向零取整的规则。例如计算 -7/3,商是 -2 (向零取整)&a…...
rust学习——环境搭建
rust安装:https://kaisery.github.io/trpl-zh-cn/ch01-01-installation.html 1、vscode装插件: toml语法支持 依赖管理 rust语法支持 2、创建demo 3、查看目录 4、执行文件的几种方式: rust安装:https://www.rust-lang.org/z…...
Linux系统中解决端口占用问题
在日常的 Linux 系统管理和开发过程中,端口占用是一个常见且令人头疼的问题。无论是部署新服务、调试应用程序,还是进行系统维护,遇到端口被占用都可能导致服务无法正常启动或运行。本文将详细介绍在 Linux 系统中如何识别和解决端口占用问题…...
现代软件架构设计:14个质量属性的定义、权衡与最佳实践
1. 引言 1.1 技术架构的重要性 技术架构是指导软件系统设计和开发的核心,它定义了系统的高层结构及关键技术选型。一个优秀的技术架构可以提高开发效率、系统稳定性和扩展能力,确保项目成功落地。面对复杂业务场景,技术架构的设计至关重要&…...
【UE5 C++课程系列笔记】25——多线程基础——FGraphEventRef的简单使用
目录 概念 使用示例1 使用示例2 概念 FGraphEventRef 本质上是对一个异步任务或者一组相关异步任务在虚幻引擎任务图系统中的一种引用(reference)。虚幻引擎的任务图系统用于高效地调度和管理各种异步任务,协调它们的执行顺序以及处理任务…...
计算机网络之---信号与编码
信号 在物理层,信号是用来传输比特流的物理量,它可以是电压、电流、光强度等形式,通常通过电缆、光纤或者无线信道等媒介传播。 信号主要分为以下两种类型: 模拟信号(Analog Signal):信号在时间…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...

