马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
1.什么是设置管理
到现在为止我们已包办理了微服务干系的几个题目:
- 微服务远程调用
- 微服务注册、发现
- 微服务哀求路由、负载均衡
- 微服务登任命户信息通报
不外,现在依然另有几个题目须要办理:
- 网关路由在设置文件中写死了,如果变动必须重启微服务
- 某些业务设置在设置文件中写死了,每次修改都要重启服务
- 每个微服务都有很多重复的设置,维护资本高
这些题目都可以通过同一的设置管理器服务办理。而Nacos不但仅具备注册中央功能,也具备设置管理的功能:
微服务共享的设置可以同一交给Nacos生存和管理,在Nacos控制台修改设置后,Nacos会将设置变动推送给干系的微服务,而且无需重启即可见效,实现设置热更新。
网关的路由同样是设置,因此同样可以基于这个功能实现动态路由功能,无需重启网关即可修改路由设置。
2.设置共享
我们可以把微服务共享的设置抽取到Nacos中同一管理,如许就不须要每个微服务都重复设置了。分为两步:
添加共享设置
以cart-service为例,我们看看有哪些设置是重复的,可以抽取的:
起首是jdbc干系设置:
留意这里的jdbc的干系参数并没有写死,比方:
- 数据库ip:通过${hm.db.host:192.168.101.129}设置了默认值为192.168.150.101,同时答应通过${hm.db.host}来覆盖默认值
- 数据库端口:通过${hm.db.port:3306}设置了默认值为3306,同时答应通过${hm.db.port}来覆盖默认值
- 数据库database:可以通过${hm.db.database}来设定,无默认值
拉取共享设置
基于NacosConfig拉取共享设置代替微服务的当地设置.
刚开始我们的项目还没有举行拉取,是一个平凡的SpringBoot项目,内部加载设置文件是如许的一个序次:项目一启动,直接去读取application.yml,它会基于这些设置去完成ApplicationContext的初始化,我们知道ApplicationContext 是Spring的bean工厂大概叫整个Spring上下文大概叫容器.
一旦引入了设置管理,那如许的项目就跟传统的SpringBoot项目不一样了,它就会参加一个SpringCloud上下文,这个SpringCloud上下文在已启动会先实验去拉取Nacos设置,基于这些设置会去完成SpringCloud上下文的ApplicatonContext的初始化.当这个初始化完成了才会去完成SpringBoot的设置文件加载和SpringBoot上下文初始化.但是题目来了: 我们的Nacos地点是设置在application.yml文件中的,现在你一上来你就要去拉取Nacos设置还没有去读取application.yml呢,如许就产生抵牾.
基于这个题目,SpringCloud引出一个新的文件bootstrap.yml [引导设置文件],项目启动先读取这个文件,我们可以把Nacos地点设置到这个文件中
文件好创建,但是文件将来被拉取,加载设置,初始化,这个过程谁来处置处罚呢?
因此,微服务整合Nacos设置管理的步调如下:
1)引入依靠:
在cart-service模块引入依靠:
- <!--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
在cart-service中的resources目次新建一个bootstrap.yaml文件:
内容如下:
- spring:
- application:
- name: cart-service # 服务名称
- profiles:
- active: dev
- cloud:
- nacos:
- server-addr: 192.168.150.101 # nacos地址
- config:
- file-extension: yaml # 文件后缀名
- shared-configs: # 共享配置
- - dataId: shared-jdbc.yaml # 共享mybatis配置
- - dataId: shared-log.yaml # 共享日志
配置 - - dataId: shared-swagger.yaml # 共享日志
配置
复制代码 3)修改application.yaml
由于一些设置挪到了bootstrap.yaml,因此application.yaml须要修改为:
- server:
- port: 8082
- feign:
- okhttp:
- enabled: true # 开启OKHttp连接池支持
- hm:
- swagger:
- title: 购物车服务接口文档
- package: com.hmall.cart.controller
- db:
- database: hm-cart
复制代码 重启服务,发现全部设置都见效了。
3.设置热更新
设置热更新: 当修改设置文件中的设置时,微服务无需重启即可使设置见效.
有很多的业务干系参数,将来大概会根据现实情况临时调解。比方购物车业务,购物车数目有一个上限,默认是10,对应代码如下:
现在这里购物车是写死的固定值,我们应该将其设置在设置文件中,方便后期修改。
但现在的题目是,即便写在设置文件中,修改了设置还是须要重新打包、重启服务才气见效。能不能不消重启,直接见效呢?
这就要用到Nacos的设置热更新本事了,分为两步:
添加设置到Nacos
起首,我们在nacos中添加一个设置文件,将购物车的上限数目添加到设置中:
留意文件的dataId格式:
[服务名]-[spring.active.profile].[后缀名]
文件名称由三部门构成:
- 服务名:我们是购物车服务,以是是cart-service
- spring.active.profile:就是spring boot中的spring.active.profile,可以省略,则全部profile共享该设置
- 后缀名:比方yaml
这里我们直接使用cart-service.yaml这个名称,则不管是dev还是local情况都可以共享该设置。
设置内容如下:
- hm:
- cart:
- maxAmount: 1 # 购物车商品数量上限
复制代码 提交设置,在控制台能看到新添加的设置:
设置热更新
接着,我们在微服务中读取设置,实现设置热更新。
在cart-service中新建一个属性读取类:
- package com.hmall.cart.config;
- import lombok.Data;
- import org.springframework.boot.context.properties.ConfigurationProperties;
- import org.springframework.stereotype.Component;
- @Data
- @Component
- @ConfigurationProperties(prefix = "hm.cart")
- public class CartProperties {
- private Integer maxItems;
- }
复制代码 接着,在业务中使用该属性加载类:
重启后举行测试即可.
4.动态路由
动态路由是Nacos设置管理的一个应用,现在我们的路由不是动态的,而是写死在网关的设置文件中的,当网关启动的时间就会去加载设置文件路由信息,生存在内存中的一个路由表内里,着实就是一个缓存,那么下次有哀求直接读取缓存就可以了,进步速率.那么这也带来了一个题目,假设我们项目运行过程中,我们的路由信息须要发生变动,那这个时间光去改设置文件就不可了,由于它已经被缓存起来了,以是你必须去重启网关服务才行,但是网关但是整个服务的入口,它怎么能恣意停机呢?它停机可想而知对整个微服务会带来非常大的影响,以是我们想实现的结果是,我们改路由立马见效不消重启网关,这就是动态路由.
监听Nacos设置变动
在Nacos官网中给出了手动监听Nacos设置变动的SDK:
https://nacos.io/zh-cn/docs/sdk.html
这里核心的步调有2步:
- 创建ConfigService,目的是毗连到Nacos
- 添加设置监听器,编写设置变动的关照处置处罚逻辑
由于我们接纳了spring-cloud-starter-alibaba-nacos-config自动装配,因此ConfigService已经在com.alibaba.cloud.nacos.NacosConfigManager中自动创建好了:


这内里还提供了getConfigService()方法

终极代码:


- package com.hmall.gateway.routers;
- import com.alibaba.cloud.nacos.NacosConfigManager;
- import com.alibaba.nacos.api.config.listener.Listener;
- import com.alibaba.nacos.api.exception.NacosException;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Component;
- import javax.annotation.PostConstruct;
- import java.util.concurrent.Executor;
- @Component
- @Slf4j
- @RequiredArgsConstructor
- public class DynamicRouteLoader {
- private final NacosConfigManager nacosConfigManager;
- private final String dataId = "gateway-routes.json";
- private final String group = "DEFAULT_GROUP";
- @PostConstruct //在这个bean初始化之后执行
- public void initRouteConfigListener() throws NacosException {
- //1.项目启动时,先拉取一个配置,并且添加配置监听器
- String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {
- @Override
- public Executor getExecutor() {//这里逻辑比较简单就不使用线程池了
- return null;
- }
- @Override
- public void receiveConfigInfo(String configInfo) {
- //2.监听到配置变更,需要去更新路由表
- updateConfigInfo(configInfo);
- }
- });
- //3.第一次读取到配置,也需要更新到路由表
- updateConfigInfo(configInfo);
- }
- public void updateConfigInfo(String configInfo){
- //TODO
- }
- }
复制代码

- package com.hmall.gateway.routers;
- import cn.hutool.json.JSONUtil;
- import com.alibaba.cloud.nacos.NacosConfigManager;
- import com.alibaba.nacos.api.config.listener.Listener;
- import com.alibaba.nacos.api.exception.NacosException;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.cloud.gateway.route.RouteDefinition;
- import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
- import org.springframework.stereotype.Component;
- import reactor.core.publisher.Mono;
- import javax.annotation.PostConstruct;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Set;
- import java.util.concurrent.Executor;
- @Component
- @Slf4j
- @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 //在这个bean初始化之后执行
- public void initRouteConfigListener() throws NacosException {
- //1.项目启动时,先拉取一个配置,并且添加配置监听器
- String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {
- @Override
- public Executor getExecutor() {//这里逻辑比较简单就不使用线程池了
- return null;
- }
- @Override
- public void receiveConfigInfo(String configInfo) {
- //2.监听到配置变更,需要去更新路由表
- updateConfigInfo(configInfo);
- }
- });
- //3.第一次读取到配置,也需要更新到路由表
- updateConfigInfo(configInfo);
- }
- public void updateConfigInfo(String configInfo){
- log.debug("监听到路由配置信息:{}",configInfo);
- // 1.解析配置信息,转为RouteDefinition
- List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);
- //2.删除旧的路由表
- for (String routeId : routeIds) {
- writer.delete(Mono.just(routeId)).subscribe();
- }
- routeIds.clear();
- //3.更新路由表
- for (RouteDefinition routeDefinition : routeDefinitions) {
- //3.1 更新路由表
- writer.save(Mono.just(routeDefinition)).subscribe();//响应式编程处理方案
- //3.2 记录路由id,便于下一次更新时删除
- routeIds.add(routeDefinition.getId());
- }
- }
- }
复制代码 重启网关,恣意访问一个接口,比如 http://localhost:8080/search/list?pageNo=1&pageSize=1:

发现是404,无法访问。
接下来,我们直接在Nacos控制台添加路由,路由文件名为gateway-routes.json,范例为json:

- [
- {
- "id": "item",
- "predicates": [{
- "name": "Path",
- "args": {"_genkey_0":"/items/**", "_genkey_1":"/search/**"}
- }],
- "filters": [],
- "uri": "lb://item-service"
- },
- {
- "id": "cart",
- "predicates": [{
- "name": "Path",
- "args": {"_genkey_0":"/carts/**"}
- }],
- "filters": [],
- "uri": "lb://cart-service"
- },
- {
- "id": "user",
- "predicates": [{
- "name": "Path",
- "args": {"_genkey_0":"/users/**", "_genkey_1":"/addresses/**"}
- }],
- "filters": [],
- "uri": "lb://user-service"
- },
- {
- "id": "trade",
- "predicates": [{
- "name": "Path",
- "args": {"_genkey_0":"/orders/**"}
- }],
- "filters": [],
- "uri": "lb://trade-service"
- },
- {
- "id": "pay",
- "predicates": [{
- "name": "Path",
- "args": {"_genkey_0":"/pay-orders/**"}
- }],
- "filters": [],
- "uri": "lb://pay-service"
- }
- ]
复制代码
无需重启网关,稍等几秒钟后,再次访问刚才的地点:
乐成了!
|