【SpringCloud】3.Nacos配置管理

专栏目录
0.docker快速入门
1.初识微服务
2.Gateway网关路由
3.Nacos配置管理

文章目录

  • 配置管理
    • 配置共享
      • 添加共享配置
      • 拉取共享配置
    • 配置热更新
      • 添加配置
      • 配置热更新
    • 动态路由
      • 监听配置
      • 删除监听
      • 更新路由
      • !实现动态路由!

配置管理

微服务拆分后,需要的重复配置过多,维护成本高
业务配置经常发生变动,每次修改都需要重启服务
网关路由配置写死后,每次变更都需要重启网关

因此需要通过统一的配置管理器服务解决。而Nacos不仅仅具备注册中心功能,也具备配置管理的功能。

微服务共享的配置可以统一交给Nacos保存和管理,在Nacos控制台修改配置后,Nacos会将配置变更推送给相关的微服务,并且无需重启即可生效,实现配置热更新。

网关的路由同样是配置,因此同样可以基于这个功能实现动态路由功能,无需重启网关即可修改路由配置。

配置共享

把微服务共享的配置抽取到Nacos中统一管理,分为两步:

  • 在Nacos中添加共享配置
  • 微服务拉取配置

添加共享配置

添加共享配置到Nacos,如JDBC、MybatisPlus、日志、Swagger、OpenFeign等配置

①在Nacos控制台中进行添加

【SpringCloud】3.Nacos配置管理_第1张图片

图片内容来自:黑马程序员

②填写表单信息以及Yaml内容

【SpringCloud】3.Nacos配置管理_第2张图片

图片内容来自:黑马程序员

一些相关的参数没有写死,而是使用${}覆盖,具体的值在application.yaml中声明

拉取共享配置

从注册中心拉取共享配置后将会和本地的application.yaml配置合并。

读取Nacos配置是SpringCloud上下文(ApplicationContext)初始化时处理的,发生在项目的引导阶段。
然后才会初始化SpringBoot上下文,去读取application.yaml
也就是说引导阶段,application.yaml文件尚未读取,根本不知道nacos 地址

因此我们需要知道的是SpringCloud初始化上下文时首先读取bootstrap.yaml文件,所有我们将nacos的地址配置到该文件即可

①引入相关依赖


<dependency>
  <groupId>com.alibaba.cloudgroupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>

<dependency>
  <groupId>org.springframework.cloudgroupId>
  <artifactId>spring-cloud-starter-bootstrapartifactId>
dependency>

②新建bootstrap.yaml在resources目录下

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 # 共享日志配置

配置热更新

配置热更新:修改配置文件中的配置时,微服务无需重启即可使配置生效

前提条件:

  • nacos中要有与微服务名有关的配置文件
    • 微服务名称-项目profile(可选).文件后缀名
    • [spring.application.name]-[spring.active.profile].[file-extension]
  • 微服务中要以特定方式读取需要热更新的配置属性
    • @ConfigurationProperties(prefix="")
    • @RefreshScope+@Value("${}")

添加配置

【SpringCloud】3.Nacos配置管理_第3张图片

图片内容来自:黑马程序员

注意dataId的命名格式

配置热更新

①创建属性读取类

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix = "demo.cart")
public class CartProperties {
    private Integer maxAmount;
}

②业务中使用该类

private CartProperties cartProperties;
...
cartProperties.getMaxAmount();
...

自此直接在nacos注册中心修改demo.cart.maxAmount的值即可生效

动态路由

网关的路由配置在项目启动时一经加载就会缓存到内存中的路由表内(Map),不会改变,也不会监听路由变更。

因此不能使用上述热更新方法,而是要用Nacos提供的手动监听配置接口来实现

监听配置

详情请见:Nacos监听配置变更-JavaSDK

①引入依赖

<dependency>
    <groupId>com.alibaba.nacosgroupId>
    <artifactId>nacos-clientartifactId>
dependency>

②使用Nacos动态监听配置接口

public void addListener(String dataId, String group, Listener listener);
参数名 参数类型 说明
dataId string 配置 ID,保证全局唯一性。
只允许英文字符和 4 种特殊字符(“.”、“:”、“-”、“_”)。
group string 配置分组,一般是默认的DEFAULT_GROUP。
listener Listener 监听器,配置变更进入监听器的回调函数。

请求示例

String serverAddr = "{serverAddr}";
String dataId = "{dataId}";
String group = "{group}";
// 1.创建ConfigService,连接Nacos
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
ConfigService configService = NacosFactory.createConfigService(properties);
// 2.读取配置
String content = configService.getConfig(dataId, group, 5000);
// 3.编写并添加配置监听器
configService.addListener(dataId, group, new Listener() {
        @Override
        public void receiveConfigInfo(String configInfo) {
        // 配置变更的通知处理
                System.out.println("recieve1:" + configInfo);
        }
        @Override
        public Executor getExecutor() {
                return null;
        }
});

删除监听

使用监听删除接口

public void removeListener(String dataId, String group, Listener listener)
参数名 参数类型 描述
dataId string 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(“.”、“:”、“-”、“_”),不超过 256 字节。
group string 配置分组
listener ConfigChangeListenerAdapter 监听器,配置变更进入监听器的回调函数。

示例

String serverAddr = "{serverAddr}";
String dataId = "{dataId}";
String group = "{group}";
// 创建ConfigService,连接Nacos
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
ConfigService configService = NacosFactory.createConfigService(properties);
// 删除监听
configService.removeListener(dataId, group, yourListener);

更新路由

更新路由使用RouteDefinitionWriter接口

/**
 * @author Spencer Gibb
 */
public interface RouteDefinitionWriter {
        /**
     * 更新路由到路由表,如果路由id重复,则会覆盖旧的路由
     */
        Mono<Void> save(Mono<RouteDefinition> route);
        /**
     * 根据路由id删除某个路由
     */
        Mono<Void> delete(Mono<String> routeId);

}
  • id:路由id
  • predicates:路由匹配规则
  • filters:路由过滤器
  • uri:路由目的地

保存到nacos的配置格式要使用JSON保存

{
  "id": "item",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"/items/**", "_genkey_1":"/search/**"}
  }],
  "filters": [],
  "uri": "lb://item-service"
}

等同于Yaml

spring:
  cloud:
    gateway:
      routes:
        - id: item
          uri: lb://item-service
          predicates:
            - Path=/items/**,/search/**

!实现动态路由!

①引入相关依赖


<dependency>
    <groupId>com.alibaba.cloudgroupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-bootstrapartifactId>
dependency>

②将gateway的resources目录创建bootstrap.yaml,添加nacos配置

spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: ip地址
      config:
        file-extension: yaml
        shared-configs:
          - dataId: shared-log.yaml # 共享日志配置

③创建监听器配置类

import ...
    
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {

    private final RouteDefinitionWriter writer;
    private final NacosConfigManager nacosConfigManager;

    // 路由配置文件的id和分组
    private final String dataId = "gateway-routes.json";
    private final String group = "DEFAULT_GROUP";
    // 保存更新过的路由id
    private final Set<String> routeIds = new HashSet<>();

    @PostConstruct
    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) {
                        updateConfigInfo(configInfo);
                    }
                });
        // 2.首次启动时,更新一次配置
        updateConfigInfo(configInfo);
    }

    private void updateConfigInfo(String configInfo) {
        log.debug("监听到路由配置变更,{}", configInfo);
        // 1.反序列化
        List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);
        // 2.更新前先清空旧路由
        // 2.1 清除旧路由
        for (String routeId : routeIds) {
            writer.delete(Mono.just(routeId)).subscribe();
        }
        routeIds.clear();
        // 2.2 判断是否有新的路由要更新
        if (CollUtils.isEmpty(routeDefinitions)) {
            // 无新路由配置,直接结束
            return;
        }
        // 3.更新路由
        routeDefinitions.forEach(routeDefinition -> {
            // 3.1.更新路由
            writer.save(Mono.just(routeDefinition)).subscribe();
            // 3.2.记录路由id,方便将来删除
            routeIds.add(routeDefinition.getId());
        });
    }
}

④在nacos注册中心后台添加路由

【SpringCloud】3.Nacos配置管理_第4张图片

图片内容来自:黑马程序员

你可能感兴趣的:(微服务,spring,cloud)