前言

Nacos 不仅仅可以作为注册中心来使用,同时它也支持作为配置中心,在 Nacos 中支持配置的优先级,本文在从源码角度来看待它们是如何按顺序优先加载的

基础配置

接下来演示一下如何使用 Nacos 配置,首先新建 Module:alibaba-vnjohn-3377

pom 文件

旧版本

spring-cloud 旧版本只需要引入一个 nacos-config 依赖即可.

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  <version>2.2.9.RELEASE</version>
</dependency>

新版本

官方文档:Spring Cloud 2021.0.1.0 版本升级指南

从 2021.0.1.0 开始,SCA 版本将会对应 Spring Cloud 版本, 前三位为 Spring Cloud 版本,最后一位为扩展版本,升级版本 (注意版本对应关系) 父模块引入依赖:

<properties>
  <java.version>1.8</java.version>
  <spring-boot-version>2.6.7</spring-boot-version>
  <spring-cloud-version>2021.0.1</spring-cloud-version>
  <spring-cloud-alibaba-version>2021.0.1.0</spring-cloud-alibaba-version>
</properties>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>${spring-boot-version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${spring-cloud-version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-dependencies</artifactId>
      <version>${spring-cloud-alibaba-version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
  </dependencies>
</dependencyManagement>

注意事项: spring-cloud-starter-alibaba-nacos-config 模块移除了 spring-cloud-starter-bootstrap 依赖,如果你想以旧版的方式使用,你需要手动加上该依赖,现在推荐使用 spring.config.import 方式引入配置

官方解释:抛弃 bootstrap 引入配置的方式,使用 spring.config.import 方式引入配置,spring boot 2.4 对这一块做了很大的优化工作,不再需要全量启动一个容器来刷新配置

本文还是以以前的方式为例,引入 spring-cloud-starter-bootstrap 依赖,若不引入这依赖,在启动时就会出现无法解析配置参数

子模块依赖引入:

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  </dependency>
  <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-bootstrap</artifactId>
  </dependency>
</dependencies>

YML 配置

在这里要配置两个,因为 Nacos 和 spring-cloud-config 一样,在项目初始化时,要保证先从配置中心进行拉取,拉取完配置以后,才能保证项目正常启动

SpringBoot 中配置文件加载是存在于优先级顺序的,优先级:application < bootstrap,这两个分别要配置的是:

application.yml

spring:
  profiles:
    # 开发环境
    active: dev

bootstrap.yml

server:
  port: 3377

spring:
  application:
    name: cloud-3377
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        namespace: 5040e7c3-c54e-4d3d-908e-70d1f2159097 # 这代表的是 dev 命名空间Id值

启动类

// 与之前的没有什么变化
@SpringBootApplication
@EnableDiscoveryClient
public class Cloud3377Application {
    public static void main(String[] args) {
        SpringApplication.run(Cloud3377Application.class, args);
    }
}

控制器类

实现配置自动更新,语义:使配置文件中的配置信息修改以后无需进行重启,即可使用到修改后的值,就可以通过 @RefreshScope 注解来实现

/**
 * @author vnjohn
 * @since 2023/2/22
 */
@RefreshScope
@RestController
public class CloudAppController {
    @Value("${cloud.name}")
    private String cloudName;

    @GetMapping("/cloud")
    public String cloud() {
        return cloudName;
    }
}

若配置了以下属性值,即使加了注解也不会生效的

spring:
  cloud:
    nacos:
      config:
        refresh-enabled: false

配置规则

官网:Nacos 配置中心官方文档

简介

在 Nacos Spring Cloud 中,dataId 的完整格式如下:

${prefix}-${spring.profiles.active}.${file-extension}
  1. prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix 来配置

  2. spring.profiles.active 即为当前环境对应的 profile,注意:spring.profiles.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}

  3. file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置,目前只支持 propertiesyaml 类型

  4. 通过 Spring Cloud 原生注解 @RefreshScope 实现配置自动更新

  5. 通过官方给出的规则我们最终需要在 Nacos 配置中心添加的配置文件的名字规则和名字为:

    # ${spring.application.name}-${spring.profiles.active}.${file-extension}
    # cloud-3377-dev.yaml
    # 微服务名称-当前环境-文件格式
    

    不过即使配置文件名字不拼接 spring.profiles.active,Nacos 默认也会帮我们加载 cloud-3377.yaml 文件的配置,具体原因可以看后面的源码讲解.

    实现不同环境之间的隔离,不一定要通过 spring.profiles.active 区分,我们可以通过 Nacos 不同的命名空间来区分,比如:dev-开发环境、test-测试环境、prod-生产环境

自动配置更新&测试

首先在 dev 命名空间下新增 dataId 名为 cloud-3377 文件,文件内容如下:

config:
    info: I'm cloud-3377 version 1

按照上面给到的代码,访问接口:http://localhost:3377/config/info,得到的值:I’m cloud-3377 version 1

此时,再修改 dataId 文件的内容:I’m cloud-3377 version 2,进行发布,再访问接口地址,得到的值:I’m cloud-3377 version 2

不同环境相同配置

在实际的开发中,项目中所用到的配置参数有时并不需要根据不同的环境来进行区分,开发、测试、生产所用到的参数是相同的,例如:端口号、应用名称;那么解决同一个服务在多个环境中,引用相同的配置问题?Nacos Config 也提供了相应的解决方案,也就是我上面说过的,即使不拼接 spring.profile.active,Nacos 也会帮我们自动加载

在这里插入图片描述

在这里就可以通过服务名+扩展名方式,来实现同一个微服务下不同环境进行共享的配置文件

在 Nacos Config 中添加配置,dataId->cloud-3377.yaml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q8ilpU2l-1677230670799)(common-cloud-config.png)]

控制器代码调整:

/**
 * @author vnjohn
 * @since 2023/2/22
 */
@RefreshScope
@RestController
public class CloudAppController {
    @Value("${cloud.name}")
    private String cloudName;
  
  	@Value("${cloud.common}")
    private String cloudCommon;

    @GetMapping("/cloud")
    public String cloud() {
        return cloudName;
    }
  
  	@GetMapping("/cloud/common")
    public String cloudCommon() {
        return cloudCommon;
    }
}

访问接口:http://localhost:3377/cloud/common,读取配置

不同微服务如何共享配置

以上 不同环境使用相同配置是最基础的配置方式,但我们在实际开发中一般会涉及到多个微服务之间共享配置;比如:redis 地址,服务注册中心公共组件等,那么这些组件是多个微服务共享的,所以我们可以使用 Nacos Config 提供的共享方式来配置共享的配置文件

在这里插入图片描述

在 Nacos 控制台中添加 common.yaml、redis.yaml

common.yaml 文件内容如下:

# 手机、邮箱正则表达式公共引入
phone:
  regex:  ^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[013,5-8]|18[0-9]|19[189])[0-9]{8}$
email:
  regex: ^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}$

common-redis.yaml 文件内容如下:

redis:
    ip: 127.0.0.1
    port: 6379

通过 shared-configs 参数进行配置引入 common.yaml 配置,调整内容如下:

spring:
  application:
    name: cloud-3377
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        namespace: 5040e7c3-c54e-4d3d-908e-70d1f2159097
        shared-configs: 
          - dataId: common.yaml
            refresh: true # 默认值为 false,不开启自动刷新,要搭配 @RefreshScope 注解一起使用
            group: DEFAULT_GROUP # 默认分组名:DEFAULT_GROUP,可以不写  
        # - 可以继续追加  

以上通过了 - 进行了配置,也可以这样进行配置:shared-configs[0].dataId、shared-configs[0].refresh,这样写只是更加美观,在配置多个的情况下能更加清晰的明白.

除了 shared-configs 进行配置,还可以通过 extension-configs 配置,配置方式和其一样,只是换了个名字,语义上更好的区分出了一个微服务有扩展配置的情况,配置 common-redis.yaml 内容如下:

spring:
  application:
    name: cloud-3377
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        namespace: 5040e7c3-c54e-4d3d-908e-70d1f2159097
        shared-configs: 
          - dataId: common.yaml
            refresh: true # 默认值为 false,不开启自动刷新,要搭配 @RefreshScope 注解一起使用
            group: DEFAULT_GROUP # 默认分组名:DEFAULT_GROUP,可以不写  
        extension-configs: 
          - dataId: common-redis.yaml
            refresh: true
        # - 可以继续追加  

从以上可以看到,这些共享配置、扩展配置也是支持配置自动刷新机制的,但它们默认是不会开启自动刷新的,若在实际业务中需要对共享或扩展配置的内容进行热部署取值,可以进行配置

整体配置优先级

Spring Cloud Alibaba Nacos Config 提供了三种配置能力从 Nacos 拉取相关的配置

A:通过 spring.cloud.nacos.config.shared-configs[n].data-id 方式支持多个共享 dataId 配置

B:通过 spring.cloud.nacos.config.extension-configs[n]-data-id 方式支持多个扩展 dataId 配置

C:通过内部相关规则(应用名、应用名+Profile)自动生成相关的 dataId 配置

当三种方式同时使用时,它们的优先级关系:A < B < C,同理,若在这三种方式中配置了同样的参数时,则会使用 C 配置的参数值

总结

该篇博文讲解在实际工作如何使用 Nacos 、配置动态刷新的运用,对 Spring Cloud 新老版本的依赖引入作了描述,从 2021.0.1.0 版本开始,移除了 spring-cloud-starter-bootstrap 依赖,最后,对配置的优先级作了区分,对不同环境配置、不同微服务如何共享配置做了详细的介绍,下篇文章让我们从源码的角度来看 Nacos 是如何加载配置的!

如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!

推荐专栏:Spring、MySQL,订阅一波不再迷路

大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐