win7 asp网站发布,网站建设服务器都有哪些,网站优化公司哪个好,什么网站做微信公众账号目录
1. 关于微服务
?1.1 微服务与单体架构的区别
?1.2 SpringCloud 技术
2. 学习前准备
?2.1 环境搭建
?2.2 熟悉项目
3. 正式拆分
?3.1 拆分商品功能模块
?3.2 拆分购物车功能模块
4. 服务调用
?4.1 介绍
?4.2 RustTemplate?的使用
4.3 服务治理-注册中…目录
1. 关于微服务
?1.1 微服务与单体架构的区别
?1.2 SpringCloud 技术
2. 学习前准备
?2.1 环境搭建
?2.2 熟悉项目
3. 正式拆分
?3.1 拆分商品功能模块
?3.2 拆分购物车功能模块
4. 服务调用
?4.1 介绍
?4.2 RustTemplate?的使用
4.3 服务治理-注册中心
4.4 服务发现
4.5 OpenFeign 技术
4.6 优化 OpenFeign
4.7 最佳实践
4.8 日志输出
5. 网关
?5.1 如何使用网关
?5.2 路由属性
?5.3 自定义 GatewayFilter 过滤器了解
?5.4?使用网关实现登录校验
5.4.1 写入用户信息
5.4.2 获取用户信息
6.配置管理扩展
6.1 共享配置
?6.1.1 配置到 Nocas 中
?6.1.2 拉取共享配置
6.2 配置热更新
6.3动态路由
?6.1?将路由配置保存到 Nacos 中可以在变更时推送给网关。
?6.2 实现更新网关中的路由配置信息。 1. 关于微服务
1.1 微服务与单体架构的区别
单体架构将业务的所有功能集中在一个项目中完成打包成一个包部署。
优点 1. 架构简单2. 部署成本低
**缺点 1.**团队协作成本高 2.系统发布效率低 3.系统可用性差无法解决高并发
总结适合开发功能相对简单规模较小的项目。 微****服务架构是服务化思想指导下的一套最佳实践架构方案。
服务化就是把单体架构中的功能模块拆分成为多个模块。
优点1.单一职责 2.团队自洽 3.服务自洽
总结微服务架构解决了单体架构存在的问题特别适合大型互联网项目的开发因此被各大互联网公司普遍采用。分布式就是服务拆分的过程其实微服务架构正式分布式架构的一种最佳实践的方案。 1.2 SpringCloud 技术
SpringCloud是目前国内使用最广泛的微服务框架集成了各种微服务功能和组件并基于 SpringBoot实现了这些组件的自动装配从而提供了良好的开箱即用体验。SpringCloud 与 SpringBoot 的版本有对应要求
SpringCloud版本
SpringBoot版本
2022.0.x aka Kilburn
3.0.x
2021.0.x aka Jubilee
2.6.x, 2.7.x (Starting with 2021.0.3)
2020.0.x aka Ilford
2.4.x, 2.5.x (Starting with 2020.0.3)
Hoxton
2.2.x, 2.3.x (Starting with SR5)
Greenwich
2.1.x
Finchley
2.0.x
Edgware
1.5.x
Dalston
1.5.x 2. 学习前准备
2.1 环境搭建
将之前在Docker学习中导入的黑马商城项目移除并且重新配置好Mysql数据库 使用 IDEA 打开资料中的hmall 项目将 application-local.yaml配置文件中的地址一栏修改为本机的虚拟机地址而后在使用 Alt 8 调出 Services 将 SpringBoot 的运行环境更改为 local 。 将资料中已经配置好的 nginx 在命令行窗口 **start nginx.exe 。**需要注意项目使用的 jdk的版本是 11 需要更改为想应的 jdk 、mybatisplus 版本为 3.4.2 。 2.2 熟悉项目
之后我们需要先熟悉 黑马商城 这个项目结构它按功能可以分为用户 商品 购物车 订单 支付 这五大部分在之后的微服务拆分中我们也是按照这五大功能来拆分的纵向拆分。 其次我们需要了解服务拆分原则
1.什么时候拆
**1创业型项目**先单体架构 快速开发快速试错随着规模扩大逐渐拆分。
**2确定的大型项目**资金充足目标明确可以直接选择微服务架构。
2.怎么拆方向
1纵向拆分按照业务模块进行拆分。
2横向拆分抽取公共服务提高复用性。
目标
**高内聚**每个微服务的取责尽量单一包含的业务关联度高完整度高。
**低耦合**每个微服务的功能要相对独立尽量减少对其他服务的依赖。
分类
**1独立的 project**拆分的每个微服务都是 project 都放入一个文件夹中项目结构上是分离的耦合度低管理困难。
2Maven 聚合拆的每个微服务作为模块包含在一个项目中。 3. 正式拆分
3.1 拆分商品功能模块
首先我们要将项目中的 商品 与购物车功能模块拆出以hmall 作为父工程在其下创建新的item-service模块导入所需的依赖创建相应结构目录创建SpringBoot 的启动类复制配置文件将端口改为 8081 避免冲突以及微服务名称、数据库名称需提前将资料中单独功能模块的数据库导入还有底部 swagger 文档配置扫描包结构的更改。 对应目录结构 将 hm-service 中与商品有关的类全部迁移到新建的 item-service 中拆分的顺序依次为domain —— mapper —— service —— controller 最后再检查是否遗漏相应的 config 配置类、enums 枚举类、utils工具类等。
到此商品功能模块的拆分就结束了再将 service 界面中的 item-service启动类的运行环境更改为 local就可以启动服务了地址栏输入localhost:8081/doc.html 进入swagger 接口文档管理界面测试接口根据 id 批量查询如下图响应成功返回状态码 200。 【Tips】 想要成功运行需要开启的程序有 资料中的 nginx 以及 Linux虚拟机中的 mysql 。 3.2 拆分购物车功能模块
拆分购物车功能模块与拆分商品功能模块的方法区别不大依照上面的步骤可以解决大部分问题但在 cart-service 功能模块中我们发现需要实现购物车中的实时显示价格距加入购物车时的变化时需要调用购物车中的相应方法而将这些方法重新引入到cart-service 功能模块中时会让代码变得冗余导致我们无法查询。 这就引出了我们要学习的新技术 ——RestTemplate远程调用 4. 服务调用
4.1 介绍
在拆分的时候我们发现一个问题就是购物车业务中需要查询商品信息但商品信息查询的逻辑全部迁移到了item-service 服务导致我们无法查询一旦服务做了拆分数据做了隔离每个服务只能使用自己的服务和数据无法使用别的服务的数据。
最终结果就是查询到的购物车数据不完整因此要想解决这个问题我们就必须改造其中的代码把原本本地方法调用改造成跨微服务的远程调用RPC即Remote Produce Call解决了微服务之间无法互相调用之间的方法的问题
原理微服务之间虽然在物理层面上被隔离开来但是在网络上是可以互通的我们可以通过网络发送请求Http来进行微服务之间的连接。
RestTemplate
Spring 提供RestTemplate 工具实现了 Http 请求的发送是 Spring 用于同步 client 端的核心类简化了与 http 服务的通信程序代码可以给它提供 URL 并提取结果。默认情况下RestTemplate 默认依赖jdk的 HTTP 连接工具。 4.2 RustTemplate的使用
使用方法
1先将 RustTemplate配置到 Spring 容器中注册成一个 Bean。 2发起远程调用。
在 service 的实现类中注入RustTemplate可以使用构造函数注入但我们可以简化。在注入的元素前加上 final修饰使之必须初始化必需使用构造函数初始化但我们可在类上加上 RequirdArgsConstructor注解代替构造函数。 restTemplate方法解析
restTemplateurl, 请求方式, 请求实体, 返回值类型, 请求参数 ****请求实体可以填 **null **在传递的返回值类型为 **List时不能使用使用字节码**它的泛型会被字节码擦除。
当Java编译器编译带有泛型的代码时它会进行类型检查以确保类型安全。但是在生成字节码时所有的泛型信息都会被擦除。泛型类型被替换为它们的原始类型即不带泛型的类型。例如ListString在运行时会被视为List所有的String类型信息都会被擦除。
所以想要解决这个问题需要创建一个对象这是参数化类型的引用。
new ParameterizedTypeReferenceListItemDTO() {}在对象的泛型中写入要传的类型它可以利用反射拿到对象的泛型。最后会返回一个响应 response。
解析响应 response
response.getbody //获取响应体
response.getStatusCode //获取响应状态码
response.getHeaders //获取响应头将 cart 与 item 两个微服务都启动后便可实现远程调用解决了微服务之间无法相互调用之间方法的问题。
存在问题
1无法解决压力大并发请求多的情况同时端口写死。无法确定端口的状态。
2服务调用者不知道服务提供者的地址当存在多个端口时该调用哪一个。
3选中的服务挂了怎么办。 4.3 服务治理-注册中心
该技术用于解决上文中 RustTemplate 存在的问题用来集中管理微服务实现服务的注册发现检查等功能 服务 A 与服务 B 注册进注册中心 C形成服务注册表表里登记了服务 A 和服务 B 的地址等相关信息。
注意可以实现功能的技术有很多他们都实现了Spring Cloud 中DiscoveryClient 这个顶级接口所以底层性质是类似的只是细节上略微不同。 服务调用者调用其他服务提供的接口通过负载均衡从提供的多个实例中选择一个。
服务提供者暴露服务接口供其他服务使用。
注册中心记录并监控微服务各实例状态推送服务变更信息。
心跳检测用于实时的检查服务提供者的状态防止调用者调取到挂掉的服务。
Nacos 注册中心组件
1.部署
提前将资料中的表导入到 Mysql 中里面包含了 Nacos 的一些相关信息同时将资料中准备好的 custom.env Nacos 配置文件连同文件夹以及打包好的 nacos.tar镜像文件移动到 虚拟机中配置文件中的 MYSQL_SERVICE_HOST 需要更改为自己的虚拟机 ip 地址。
使用 docker load -i nacos.tar命令加载镜像最后再使用 docker run 命令启动 nacosmysql 要先于 nacos 启动因为 nacos 的一些数据储存在 mysql 数据库中如用户名密码等。
docker run -d –name nacos –env-file ./nacos/custom.env -p 8848:8848 -p 9848:9848 -p 9849:9849 –restartalways nacos/nacos-server:v2.1.0-slim
启动 Nacos 后使用浏览器可以访问http://【你的虚拟机ip地址】:8848/nacos来进入nacos 官方的控制平台使用数据库中的用户名和密码登录账号密码都是 nacos以后就可以在此页面监控和查看你已在其中注册的微服务。 接下来我们需要在 项目中 引入 nacos的依赖同时完成 nacos 的地址的配置。
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId
/dependency地址处为自己虚拟机的 ip 地址 可以看到这时将服务启动后 nacos 的服务管理中出现了对应的功能模块我们还可以点击详情查看关于单个服务的具体信息如实例数等。 4.4 服务发现
服务调用者想要去 nacos 订阅服务提供者的过程叫做服务发现我们需要先引入依赖 接着再去配置地址步骤与服务治理中的配置方法一致**。**
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId
/dependency然后我们就可以去使用它了先在实现类中注入DiscoveryClient 然后就可以去订阅其它微服务动态感知服务提供者的地址解决了地址写死的问题。 1根据微服务的名称获取事务的服务列表判断其不为 null。
2使用负载均衡算法中的随机选择一个实例使用
3使用 getUri( )方法获取 url 拼接成一串地址。 4.5 OpenFeign 技术
上面使用的方法还是太冗杂繁琐了仅仅是调用一个微服务中的方法就写了超过10行代码所以我们学习了简化这个操作的新技术——OpenFeign它简化了繁琐的代码是一种声明式的 Http 客户端。
使用方法
**1.**引入依赖 dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-loadbalancer/artifactId/dependency**2.**在启动类上加上 EnableFeignClient开关注解
**3.**定义一个接口用于编写 Feign 客户端 FeignClient“服务名” GetMapping“完整的请求路径”
方法与具体微服务中要调用的方法参数与原本方法一致不用实现。
**4.**调用方法
在实现类中注入已经写好的 FeignClient 接口接着调用接口中的方法获取到商品feign 替我们完成了服务拉取、负载均衡、发送 http 请求的所有工作简化了原本繁琐的操作。 4.6 优化 OpenFeign
Feign 底层发起 http 请求依赖于其它的框架。其底层支持的 http 客户端实现包括 HttpURLConnection默认实现不支持连接池这意味着每次 HTTP 请求都需要建立一个新的连接并在请求完成后关闭连接。这种方式在处理大量并发请求时会导致性能瓶颈因为连接的建立和关闭都需要消耗时间和资源。 Apache HttpClient 支持连接池可以显著提高性能因为连接池允许 Feign 复用已经建立的连接而不是每次请求都重新建立连接。这样可以减少连接的建立和关闭次数降低资源消耗提高请求的响应速度和吞吐量。 OKHttp支持连接池。与 Apache HttpClient 类似OKHttp 通过连接池来复用连接提高请求的效率。此外OKHttp 还提供了异步请求、缓存等功能进一步增强了其性能和灵活性。
使用步骤
**1**引入 OKHttp 依赖
dependencygroupIdio.github.openfeign/groupIdartifactIdfeign-okhttp/artifactId
/dependency**2**在配置中开启连接池功能 重启服务后连接池就生效了。
4.7 最佳实践
解决重复代码问题 思路一抽取到微服务之外的公共module 思路二每个微服务自己抽取一个module
方案一抽取更加简单工程结构也比较清晰但缺点是整个项目耦合度偏高。
方案二抽取相对麻烦工程结构相对更复杂但服务之间耦合度降低。
为了避免代码的复用性过高选择思路一进行实现不必在每个模块中都编写 Client 接口以及各种 dto 对象我们可以将其再次拆分重新聚合成一个 api 模块统一将要调用的 dto 与 Client 写入一个模块中之后在有需求的模块中引入 api 模块解决重复代码问题。
而因为 ItemClient 现在定义到了 com.hmall.api.client 包下而 cart-service 的启动类定义在 com.hmall.cart 包下扫描不到 ItemClient所有我们要在启动类的EnableFeignClient中加上 api 中 client 所在的路径**( “com.hmall.api.client” ) **或声明要使用的 Client ( clients {ItemClient.class} ) 。 4.8 日志输出
OpenFeign 只会在 Client 所在包的日志级别为 DeBug 时才会输出日志且日志级别有4级
**NONE**不记录任何日志信息默认。
BASIC仅记录请求的方法URL及响应状态码和执行时间。
HEADER在 BASIC 的基础上额外记录了请求和响应的头信息。
FULL记录所有的请求和响应的明细包括头信息、请求体、元数据。
开启步骤
1需在 api 模块声明一个 Logger.level 的 Bean。在其中定义日志级别。 21.在 FeignClient中声明 configuration Logger.level 所在配置文件名局部
2.在启动类上的EnableFeignClientdefaultConfiguration 配置文件.class全局
调试中可以看到日志输出。 5. 网关
5.1 如何使用网关
网关就是网络的关口负责请求的路由、转发、身份校验。相当于一个小区的保安所有的请求都需要发送到网关由它进行统一的校验和转发并通过负载均衡选择一个微服务进行转发以及通过注册中心拉取相应微服务的地址。对前端来说只需将请求地址变为网关的地址与单体架构无异且里面的微服务相对而言是隐藏的增加了安全性。
在 SpringCloud 中网关的实现包括两种
1. Spring Cloud Gateway
Spring 官方出品基于 WebFlux 响应式编程性能优异。荐
2.Netflie Zuul
Netflie 出品基于Servlet 的阻塞式编程需要调优才能获得与前者类似的性能现在已停止维护。
使用步骤
1在 hmall 父模块下创建新的模块 hm-gateway 。
2引入依赖 dependencies!--common--dependencygroupIdcom.heima/groupIdartifactIdhm-common/artifactIdversion1.0.0/version/dependency!--网关--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-gateway/artifactId/dependency!--nacos discovery--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependency!--负载均衡--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-loadbalancer/artifactId/dependency/dependenciesbuildfinalName${project.artifactId}/finalNamepluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build
/project3编写启动类 4配置路由规则
新建 ymal 配置文件在其中配置 port端口号、name微服务名、server-addr服务拉取 nacos 地址、以及 routes路由规则。 其中id 为微服务名称**uri** 为路由目标lb为负载均衡协议后跟 /服务名称predicates 下接具体的参数 - name 路由规则名 与 - args 参数 可简写为图中 -路由规则名参数而多个colltroller 中的请求路径可以在其下方按规则接着写也可在其后方使用 ‘,’ 隔开接着写。
成功启动项目后可以看到无论是 8081 端口还是 8080 端口gateway模块都可以成功的查询到商品的数据证明了网关服务成功的实现了。 5.2 路由属性
进入源码中查看 id路由的唯一标识。
uri路由目标地址。
predicates路由断言判断请求是否符合当前路由。
filters路由过滤器对请求或响应做特殊处理。
Spring 提供了 12 种路由断言
名称
说明
示例
After
是某个时间点后的请求
- After2037-01-20T17:42:47.789-07:00[America/Denver]
Before
是某个时间点之前的请求
- Before2031-04-13T15:14:47.43308:00[Asia/Shanghai]
Between
是某两个时间点之前的请求
- Between2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie
请求必须包含某些cookie
- Cookiechocolate, ch.p
Header
请求必须包含某些header
- HeaderX-Request-Id, d
Host
请求必须是访问某个host域名
- Host**.somehost.org,**.anotherhost.org
Method
请求方式必须是指定方式
- MethodGET,POST
Path
请求路径必须符合指定规则
- Path/red/{segment},/blue/**
Query
请求参数必须包含指定参数
- Queryname, Jack或者- Queryname
RemoteAddr
请求者的ip必须是指定范围
- RemoteAddr192.168.1.1/24
weight
权重处理
-Weightgroup1,2
XForwarded Remote Addr
基于请求的来源IP做判断
-XForwardedRemoteAddr192.168.10.100/24
以及网关中提供的 33 种路由过滤器每种过滤器都有其独特的功能。
配置的默认过滤器对所有路由都生效。
网关请求处理流程 HeadlerMapping路由映射器基于路由断言进行匹配**。 ——WebHeadler请求处理器**找到当前请求对应路由生效的过滤器放到过滤器链中排序依次执行。—— NettyRouting Filter默认在所有路由中都生效在过滤器链的最后执行负责将请求转发到微服务当返回结果后将其存入上下文中并按来时顺序依次返回执行 post 逻辑。
网关内部含有两个逻辑pre 和 post在请求路由到微服务之前和之后执行如果 pre 逻辑中的任何检查失败网关将拦截请求并直接返回错误响应给客户端而不会将请求转发到后端的微服务接收到微服务的响应后网关执行 post 逻辑。 5.3 自定义 GatewayFilter 过滤器了解
1实现 AbstractGatewayFilterFactory 工厂实现 apply 方法返回一个过滤器我们也可以选择实现装饰类 Ordered 来控制过滤器的执行顺序。
2自定义一个类用于接受配置的参数。
3使用本类的构造函数调用父类的构造函数将自定义的参数类的字节码传递给父类让它帮我们读取配置固定的类名称后缀 GatewatFilterFactory。
4实现 shortcutFieldOrder 方法其中返回收集的参数。 在application.yaml配置文件中可以配置default-filters 为构造函数前缀名参数。 5.4使用网关实现登录校验
**1**如何在网关转发之前做登录校验
在网关内自定义一个过滤器 pre逻辑 进行 JWT 校验。
**2**网关如何将信息传递给微服务
将得到的用户信息存放在请求头中发送请求到微服务由微服务获取请求头。
**3**如何在微服务之间传递用户信息
与第二个问题解决方法类似但微服务之间由 Openfeign 发起具体实现有所不同。
网关过滤器
1GatewayFilter路由过滤器作用于任意指定的路由默认不生效要配置到路由后生效。
2GlobalFliter全局过滤器global全局作用范围是所有路由声明后自动生效。
两种方法的底层过滤方法签名完全一致都是 filter 方法。
【Tips】方法签名由方法名、参数、返回值构成。 filter 方法中第一个参数是请求上下文包含整个过滤器连内共享的数据。第二个参数是过滤器链当前过滤器执行完后要调用下一个过滤器将链条串起来。返回值 Mono 可以调用你写的回调函数完成post 逻辑不用等待是一种非阻塞式的编程但现在用不到。
代 码 实 现
5.4.1 写入用户信息
首先将必备的 config 配置文件**、util** 工具类**、以及关于 jwt 和 排除路径 配置到 application.yaml配置文件中。**
hm:jwt:location: classpath:hmall.jksalias: hmallpassword: hmall123tokenTTL: 30mauth:excludePaths:- /search/**- /users/login- /items/**创建一个新的拦截器使用 Component 标记该类为 Bean同时实现 GlobleFilter 和 Ordered。
1获取 Request
我们可以直接从上下文中获取到请求 request 。 2判断是否要做登录拦截
通过我们自己定义的 isExclude 方法来判断请求路径是否是要排除的路径使用 request.getPath () 获取请求注入 AuthProperties存放了放行的请求路径 来获取放行的请求路径在判断方法中遍历获取放行路径由于两种路径的格式不同我们需要使用 Spring 提供的 AntPathMatcher匹配器来进行比对使用AntPathMatcher.match(参数1参数2) 来比较。 3获取 token
通过获取上下文exchange 中请求头里规定好的 authorization参数来获取请求头。
4校验并验证 token
注入 util 包中的 JwtTool后使用其中提供好的parseToken () 方法来校验之后使用 try-catch 捕获异常在其中通过上下文 exchange 获取响应response 并将状态码设置为 401 **HttpStatus.UNAUTHORIZED**表示用户未登录最后返回 response.setComplete() 终止后续拦截器不再进行请求也不再转发。 5传递用户信息
使用上下文exchange 中提供好的 mutate () 方法就可以对上下文内容进行修改写入的请求头要规定好名称方便读取。 6放行
最后使用return chain.filter(webExchange)将修改好的上下文传入放行给下一个过滤器。
5.4.2 获取用户信息
由于最后是将用户信息存放在请求头中传递所以我们需要用到学过的拦截器来将请求拦截获取用户信息但每一个微服务都可能需要获取用户的信息所以我们不能在每一个微服务里都写一个拦截器所以我们需要将拦截器写在common 模块中避免重复编写。
因为在过滤器中已经写好了登录校验的逻辑所以在拦截器中不需要拦截任何请求全部放行只需获取其中的用户信息即可。但在微服务的远程调用中例如在购物车中提交订单后删除购物车中商品时还需要用户信息微服务之间是用 OpenFeign 远程调用的所以需要在它们之间定义一个拦截器将由网关转发请求而被拦截保存的用户信息再次写入到远程调用的请求头中从而成功传递用户信息。 1在 hm-common 模块中定义一个拦截器使之能对所有微服务生效。
1.1 实现HandlerInterceptor 并重写其中的**preHandle请求处理前被调用**和 afterCompletio整个请求结束后被调用。
1.2preHandle 中获取到用户信息存入ThreadLocal 中后放行。 1.3afterCompletion 中在所有业务完成后清理用户信息。 2想要拦截器生效还需在配置中添加拦截器在 config 包下定义 MvcConfig 配置类实现 WebMvcConfigurer 接口在addInterceptors 方法中添加拦截器不配置默认拦截所有请求。 配置类想要生效需要被扫描到但包不同无法扫描到。而想要被扫描到需要在 resources 下的 META-INF 包下定义一个文件记录。 而在网关中引入了 common 的依赖但我们不需要 MvcConfig 配置且两者之间底层不同网关底层是非阻塞式的、响应式编程基于WebFlux而非 SpringMvc所以我们需要使用ConditionalOnClass 条件注解在其中加入 SpringMvc 的核心 Api 作为条件进行排除使之不在网关中生效。 3OpenFeign 传递用户信息
使用 OpenFeign 中提供好的拦截器接口之后所有由 OpenFeign 发起的请求都会先调用拦截器处理请求。 我们需要将其定义在所有微服务都引到的 api 模块中又因为其功能较单一我们可以将其写为匿名内部类但因为我们将用户信息存入请求头中需要先获取所以要在 pom 文件中引入 common 模块。 6.配置管理扩展
在微服务、网关等模块里存在大量重复的配置维护的成本高且每一次配置变更都需重启微服务网关的路由配置也是写死的更改起来繁琐因而引出了我们要学习的新技术——配置管理。
将配置统一分功能写入到配置管理中在由微服务拉取配置在配置变更时实时推送变更到微服务中。说是新技术实则是我们此前学习过的 Nacos 中的配置管理组件我们需要学习的只有功能的使用方法——共享配置、配置热更新、动态路由。 6.1 共享配置
6.1.1 配置到 Nocas 中
将 pom 配置文件中公共的配置写入到 Nacos 的配置管理中例如 jdbc、MybatisPlus、日志、swgger、OpenFeign 等配置配置后可点击详情查看。 我们使用 yaml 格式配置在其中可以使用 ${ } 去动态的读取配置中的变量。像端口配置这种默认为 3306 的也可在其后加上 :3306 定义一个默认值如果没有在项目中配置默认端口就为 3306 。同理别的配置也可以这样配置成动态的去读取避免写死**。** 6.1.2 拉取共享配置
基于NacosConfig 拉取共享配置代替为服务的本地配置但想要在服务启动时拉取 Nacos 的配置必须要知道 Nacos 的地址而地址又配置在了 SpringBoot 的配置文件中所以我们要用bootstrap.yaml 文件在其中配置相关信息项目启动首先就会去读取其中的配置获取到 Nacos 的地址最后将 Nacos 的配置与 SpringBoot 中的配置合并。 1引入依赖 !--nacos配置管理--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-config/artifactId/dependency!--读取bootstrap文件--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-bootstrap/artifactId/dependency2新建 bootstrap.yaml 文件
将 yaml 文件的配置复制到其中删掉不需要的并加上 config 配置 Nacos 配置。 file-extension 表示配置文件的后缀名在shared-configs 下配置共享配置。
**- date-id**配置管理中配置的名字 配置好后修改原有 application.yaml配置文件中的内容删除与 Nacos 中相同内容的配置并在其中写好要读取的变量例如数据库名称swagger 标题等。 可以看到启动后的日志中正在读取 Nacos 中的配置文件。 6.2 配置热更新
配置热更新后当我们修改项目中的一些配置时我们无需重启服务就可以使配置生效。
前提条件
1Nacos 要有一个与微服务名称有关的配置文件
例 微服务名称-项目profile例dev可选填.文件名后缀
spring.applicaition.name-spring.profiles.active.file-extension
但我们会发现这些已经在之前的 bootstrap 文件中写好****它会自动读取。 2微服务中要以特定的方式读取需要热更新的配置属性
1.Properties 读取推荐 2. Value 注解读取 案例将购物车的上限更改为读取配置文件的属性交给 Nacos 管理实现热更新。
**1.**编写 Properties 类在其中定义一个变量 maxItems。
ConfigurationProperties(prefix “hm.cart”) 作用是将其与配置文件中前缀为 hm.cart 的属性绑定在一起加上 Component 使其生效。 2.在业务层注入CartProperties将业务中的固定的数10 修改为从中读取数据。
2.在 Nacos 中配置
起名遵守前提条件一微服务名称-项目profile例dev可选填.文件名后缀
配置内容遵循 ConfigurationProperties 注解中的描述 配置完成热部署后我们将 maxItems 设置为 2 测试 测试成功 6.3动态路由
我们知道路由是写死在网关的配置文件中加载后保存在一个路由表的缓存中以后会直接读取缓存提高处理速度但这样我们修改配置文件中路由后想要生效就只能重启网关想要解决这个问题就需要我们利用 Nacos 实现动态路由。
6.3.1将路由配置保存到 Nacos 中可以在变更时推送给网关。
我们使用 json 格式来配置是为了更方便的解析配置信息对 json 格式更加熟悉可以使用工具类进行解析。 6.3.2实现更新网关中的路由配置信息。
**1**监听 Nacos 配置解析
需要先读取一次配置在监听配置的变化而 alibaba 包中的自动装配里提供了一个已经装配好的 BeanNacosConfigManager 只需将其注入调用其方法就可获取ConfigService省去了官方文档中第一步的操作。
而 CongfigService 提供了getConfigAndSignListener 方法可以先拉取配置再注册监听器将步骤二中的两次操作合二为一最终简化代码。 2 引入依赖并配置
!--统一配置管理--
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-config/artifactId
/dependency
!--加载bootstrap--
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-bootstrap/artifactId
/dependency新建 bootstrap 配置文件配置相关信息 以及将 application.yaml 文件中删除路由信息及无关配置。 最后再创建监听器类自定义一个初始化路由监听器的方法在其上加上 PostConstruct 注解使其在 Bean 初始化之后执行注入NacosConfigManager 调用其方法先拉取配置再添加监听器参数 dataId、group 与 Nacos 配置管理中的一一对应将其定义为变量传入。新建的监听器中getExecutor 用来定义一个线程池但我们的逻辑简单不需要用到。receiveConfigInfo 方法表示当配置变更时要干什么所以我们需要更新到路由表。在最后我们要将第一次读取到的配置更新到路由表中。 而更新路由表需要用到新的 api 名为 RouteDefinitionWrite 将其注入到类中调用其中 save 和 delete 方法可以更新路由表的内容。我们先试用 JSONUtil 工具包中的方法将传来的 json格式信息转为RouteDefinition 类型然后根据 Id 遍历删除旧的路由表开始时 Id 为 null 在第一次读取后利用定义的 Set 集合容器记录下来便于下一次更新时删除。之后遍历更新 save 路由信息需传入SpringBoot 提供的一个响应式编程的容器可以用 Mono 容器的 just 方法将数据装入之后跟 subscribe方法表示订阅容器中的消息只在其有消息后才去处理。 将项目启动后添加 Nacos 网关路由的配置无需重启即可读取到配置信息成功访问到网址内容并在控制台输出监听到的路由配置信息。 有什么问题欢迎指出。
【完结】