Spring Boot 配置中心 Nacos 入门

1. 概述

《Nacos 极简入门》中,我们已经学习了如何搭建一个 Nacos 服务。如果还没有的胖友,赶紧先去简单学习下,重点是跟着该文「2. 单机部署」小节,自己搭建一个 Nacos 服务。

本文,我们来学习下如何在 Spring Boot 中,将 Nacos 作为一个配置中心,实现分布式环境下的配置管理。

友情提示:对 Nacos 作为注册中心感兴趣的胖友,可以看看《芋道 Spring Boot 注册中心 Nacos 入门》文章。

2. 快速入门

示例代码对应仓库:lab-44-nacos-config-demo

本小节,我们会在 Nacos 服务中定义配置,并使用 @ConfigurationProperties 和 @Value 注解,读取该配置。

友情提示:如果胖友看过《Spring Boot 配置文件入门》「2. 自定义配置」小节,就会发现本小节是对标这块的内容。

如果没看过,也没关系,艿艿只是提一下而已,嘿嘿。继续往下看即可。

2.1 引入依赖

在 pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-44-nacos-config-demo</artifactId>

    <dependencies>
        <!-- Spring Boot Starter 基础依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- 实现对 Nacos 作为配置中心的自动化配置 -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-starter</artifactId>
            <version>0.2.4</version>
        </dependency>
    </dependencies>

</project>

2.2 配置文件

在 application.yml 中,添加 Nacos 配置,如下:

nacos:
  # Nacos 配置中心的配置项,对应 NacosConfigProperties 配置类
  config:
    server-addr: 127.0.0.1:18848 # Nacos 服务器地址
    bootstrap:
      enable: true # 是否开启 Nacos 配置预加载功能。默认为 false。
      log-enable: true # 是否开启 Nacos 支持日志级别的加载时机。默认为 false。
    data-id: example # 使用的 Nacos 配置集的 dataId。
    type: YAML # 使用的 Nacos 配置集的配置格式。默认为 PROPERTIES。
    group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP。
    namespace: # 使用的 Nacos 的命名空间,默认为 null。

nacos.config 配置项,为 Nacos 作为配置中心的配置,对应 NacosConfigProperties 配置类。

  • server-addr:Nacos 服务器地址。

  • bootstrap.enable:是否开启 Nacos 配置预加载功能。默认为 false。😈 这里,我们设置为 true,保证使用 @Value 和 @ConfigurationProperties 注解,可以读取到来自 Nacos 的配置项。

  • bootstrap.log-enable:是否开启 Nacos 支持日志级别的加载时机。默认为 false。😈 这里,我们设置为 true,保证 Spring Boot 应用的 Logger 能够使用来自 Nacos 的配置项。

  • data-id:使用的 Nacos 配置集的 dataId。😈 这里,我们设置为 example,稍后会去创建。

    FROM 《Nacos 文档 —— Nacos 概念》

    配置集
    一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件通常就是一个配置集,包含了系统各个方面的配置。例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。

    配置集 ID
    Nacos 中的某个配置集的 ID。配置集 ID 是组织划分配置的维度之一。Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有意义的名称标识。Data ID 通常采用类 Java 包(如 com.taobao.tc.refund.log.level)的命名规则保证全局唯一性。此命名规则非强制。

  • type:使用的 Nacos 配置集的配置格式。默认为 PROPERTIES。这里,我们设置 YAML,对应 YAML 格式的配置格式。

  • group:使用的 Nacos 配置分组,默认为 DEFAULT_GROUP。😈 这里,我们设置为 DEFAULT_GROUP,就是默认值。

    FROM 《Nacos 文档 —— Nacos 概念》

    配置分组
    Nacos 中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串(如 Buy 或 Trade )对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如 database_url 配置和 MQ_topic 配置。

  • namespace:使用的 Nacos 的命名空间,默认为 null。😈 稍后,我们会通过 namespace 配置项,基于 Nacos 的多环境不同配置的功能。

    FROM 《Nacos 文档 —— Nacos 概念》

    命名空间
    用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。

😜 突然看到 Nacos 一大片的概念,胖友会有点懵逼。问题不大,跟着示例继续往下,会逐步有感觉的。

更多 Nacos Config Spring Boot 配置项,可以看看《nacos-spring-boot-project —— WIKI》文章。

2.3 创建 Nacos 配置集

① 打开 Nacos UI 界面的「配置列表」菜单,进入「配置管理」功能。如下图所示:配置管理

② 点击列表右上角的➕号,进入「新建配置」界面,创建一个 Nacos 配置集。输入如下内容,并点击「发布」按钮,完成创建。如下图所示:新建配置

其中,YAML 配置文件如下:

order:
  pay-timeout-seconds: 120 # 订单支付超时时长,单位:秒。
  create-frequency-seconds: 10 # 订单创建频率,单位:秒

2.4 OrderProperties

创建 OrderProperties 配置类,读取 order 配置项。代码如下:

@Component
@ConfigurationProperties(prefix = "order")
// @NacosConfigurationProperties(prefix = "order", dataId = "${nacos.config.data-id}", type = ConfigType.YAML)
public class OrderProperties {

    /**
     * 订单支付超时时长,单位:秒。
     */
    private Integer payTimeoutSeconds;

    /**
     * 订单创建频率,单位:秒
     */
    private Integer createFrequencySeconds;

    // ... 省略 set/get 方法

}
  • 在类上,添加 @Component 注解,保证该配置类可以作为一个 Bean 被扫描到。
  • 在类上,添加 @ConfigurationProperties 注解,并设置 prefix = "order" 属性,这样它就可以读取前缀为 order 配置项,设置到配置类对应的属性上。

😈 这里,我们注释了一段 @NacosConfigurationProperties 注解的代码,该注解在功能上是对标 @ConfigurationProperties 注解,用于将 Nacos 配置注入 POJO 配置类中。为什么我们这里注释掉了呢?因为我们在「2.2 配置文件」中,设置了 nacos.config.bootstrap.enable=true,Spring Boot 应用在启动时,预加载了来自 Nacos 配置,所以可以直接使用 @ConfigurationProperties 注解即可。这样的好处,是可以更加通用,而无需和 Nacos 有耦合与依赖。

2.5 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

@SpringBootApplication
// @NacosPropertySource(dataId = "example", type = ConfigType.YAML)
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Component
    public class OrderPropertiesCommandLineRunner implements CommandLineRunner {

        private final Logger logger = LoggerFactory.getLogger(getClass());

        @Autowired
        private OrderProperties orderProperties;

        @Override
        public void run(String... args) {
            logger.info("payTimeoutSeconds:" + orderProperties.getPayTimeoutSeconds());
            logger.info("createFrequencySeconds:" + orderProperties.getCreateFrequencySeconds());
        }

    }

    @Component
    public class ValueCommandLineRunner implements CommandLineRunner {

        private final Logger logger = LoggerFactory.getLogger(getClass());

//        @NacosValue(value = "${order.pay-timeout-seconds}")
        @Value(value = "${order.pay-timeout-seconds}")
        private Integer payTimeoutSeconds;

//        @NacosValue(value = "${order.create-frequency-seconds}")
        @Value(value = "${order.create-frequency-seconds}")
        private Integer createFrequencySeconds;

        @Override
        public void run(String... args) {
            logger.info("payTimeoutSeconds:" + payTimeoutSeconds);
            logger.info("createFrequencySeconds:" + createFrequencySeconds);
        }
    }

}

① 在 Application 类上,我们注释了一段 @NacosPropertySource 注解,该注解用于声明从 Nacos 读取的配置集。为什么我们整列注释掉了呢?因为我们在「2.2 配置文件」中,通过 nacos.config.data-idnacos.config.type 等配置项,已经设置从 Nacos 读取的配置集。该配置一般用于在 Spring 应用中,使用 Nacos 作为配置中心。

② 在 OrderPropertiesCommandLineRunner 类中,我们测试了使用 @ConfigurationProperties 注解的 OrderProperties 配置类,读取 order 配置项的效果。

③ 在 ValueCommandLineRunner 类中,我们测试了使用 @Value 注解,读取 order 配置项的效果。😈 这里,我们注释了一段 @NacosValue 注解的代码,该注解在功能上是对标 @Value 注解,用于将 Nacos 配置注入属性种。为什么我们这里注释掉了呢?原因同 @NacosConfigurationProperties 注解。

友情提示:

  • @Value 注解,是 Spring 所提供。
  • @ConfigurationProperties 注解,是 Spring Boot 所提供。

下面,我们来执行 Application 的 #main(String[] args) 方法,启动 Spring Boot 应用。输出日志如下:

# 从 Nacos 中,读取 example 配置集。
2020-01-22 11:49:11.679  INFO 8430 --- [           main] c.a.b.n.c.u.NacosConfigPropertiesUtils   : nacosConfigProperties : com.alibaba.boot.nacos.config.properties.NacosConfigProperties@6ff29830
2020-01-22 11:49:12.018  INFO 8430 --- [           main] c.a.b.n.config.util.NacosConfigUtils     : load config from nacos, data-id is : example, group is : DEFAULT_GROUP

# ValueCommandLineRunner 输出
2020-01-22 11:49:12.745  INFO 8430 --- [           main] s.l.n.Application$ValueCommandLineRunner : payTimeoutSeconds:120
2020-01-22 11:49:12.746  INFO 8430 --- [           main] s.l.n.Application$ValueCommandLineRunner : createFrequencySeconds:120

# OrderPropertiesCommandLineRunner 输出
2020-01-22 11:49:12.746  INFO 8430 --- [           main] ication$OrderPropertiesCommandLineRunner : payTimeoutSeconds:120
2020-01-22 11:49:12.746  INFO 8430 --- [           main] ication$OrderPropertiesCommandLineRunner : createFrequencySeconds:10
  • 两个 CommandLineRunner 都读取 order 配置项成功,美滋滋。

友情提示:艿艿自己尝试了在《芋道 Spring Boot 配置文件入门》的如下小节的功能,都可以完美支持:

3. 多环境配置

示例代码对应仓库:lab-44-nacos-config-demo-profiles

《芋道 Spring Boot 配置文件入门》「6. 多环境配置」中,我们介绍如何基于 spring.profiles.active 配置项,在 Spring Boot 实现多环境的配置功能。在本小节中,我们会在该基础之上,实现结合 Nacos 的多环境配置。

实际上,Nacos 开发者已经告诉我们如何实现了,通过 Nacos namespace 命名空间。文档说明如下:

FROM 《Nacos 文档 —— Nacos 概念》

命名空间
用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。

如此,我们可以通过给每个环境创建一个 Nacos namespace。然后,在每个 application-${profile}.yaml 配置文件中,配置对应的 Nacos namespace。

下面,我们来搭建一个结合 Nacos 的多环境的示例。

首先,让我们进行 Nacos 命名空间和配置集的创建。

3.1 创建 Nacos 命名空间

① 打开 Nacos UI 界面的「命名空间」菜单,进入「命名空间」功能。如下图所示:命名空间

② 点击列表右上角的「新建命名空间」按钮,弹出「新建命名空间」窗口,创建一个 dev 命名空间。输入如下内容,并点击「确定」按钮,完成创建。如下图所示:新建命名空间

③ 重复该操作,继续创建一个 prod 命名空间。最终 dev 和 prod 信息如下图:命名空间列表

3.2 创建 Nacos 配置集

① 打开 Nacos UI 界面的「配置列表」菜单,进入「配置管理」功能。如下图所示:配置管理

我们会发现,红圈部分多了 dev 和 prod 两个命名空间。

② 点击 dev 命名空间,然后点击列表右上角的➕号,进入「新建配置」界面,创建一个 Nacos 配置集。输入如下内容,并点击「发布」按钮,完成创建。如下图所示:新建配置

③ 点击 prod 命名空间,然后点击列表右上角的➕号,进入「新建配置」界面,创建一个 Nacos 配置集。输入如下内容,并点击「发布」按钮,完成创建。如下图所示:新建配置

如此,我们在 Nacos 中有 devprod 命名空间。而这两命名空间下,都有一个 example 配置集。而这两配置集都有 server.port 配置项,用于启动不同端口的服务器。😈 为什么选择 server.port 配置呢?因为 Spring Boot 项目启动后,从日志中就可以看到生效的服务器端口,嘿嘿~

然后,让我们进行 Spring Boot 示例的搭建。

3.3 引入依赖

在 pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-44-nacos-config-demo-profiles</artifactId>

    <dependencies>
        <!-- 实现对 SpringMVC 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 实现对 Nacos 作为配置中心的自动化配置 -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-starter</artifactId>
            <version>0.2.4</version>
        </dependency>
    </dependencies>

</project>
  • 引入 spring-boot-starter-web 原来的原因是,我们会使用 server.port 配置项,配置 Tomcat 的端口。

3.4 配置文件

在 resources 目录下,创建 2 个配置文件,对应不同的环境。如下:

nacos:
  # Nacos 配置中心的配置项,对应 NacosConfigProperties 配置类
  config:
    server-addr: 127.0.0.1:18848 # Nacos 服务器地址
    bootstrap:
      enable: true # 是否开启 Nacos 配置预加载功能。默认为 false。
      log-enable: true # 是否开启 Nacos 支持日志级别的加载时机。默认为 false。
    data-id: example # 使用的 Nacos 配置集的 dataId。
    type: YAML # 使用的 Nacos 配置集的配置格式。默认为 PROPERTIES。
    group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP。
    namespace: 14226a0d-799f-424d-8905-162f6a8bf409 # 使用的 Nacos 的命名空间,默认为 null。
nacos:
  # Nacos 配置中心的配置项,对应 NacosConfigProperties 配置类
  config:
    server-addr: 127.0.0.1:18848 # Nacos 服务器地址
    bootstrap:
      enable: true # 是否开启 Nacos 配置预加载功能。默认为 false。
    log-enable: true # 是否开启 Nacos 支持日志级别的加载时机。默认为 false。
    data-id: example # 使用的 Nacos 配置集的 dataId。
    type: YAML # 使用的 Nacos 配置集的配置格式。默认为 PROPERTIES。
    group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP。
    namespace: f1686f3b-a984-4cdf-8298-7caee3455d14  # 使用的 Nacos 的命名空间,默认为 null。

另外,我们会创建 application.yaml 配置文件,放不同环境的相同配置。例如说,spring.application.name 配置项,肯定是相同的啦。配置如下: 

spring:
  application:
    name: demo-application

3.5 ProfilesApplication

创建 ProfilesApplication.java 类,配置 @SpringBootApplication 注解即可。代码如下:

@SpringBootApplication
public class ProfilesApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProfilesApplication.class, args);
    }

}

3.6 简单测试

下面,我们使用命令行参数进行 --spring.profiles.active 配置项,实现不同环境,读取不同配置文件。

① 开发环境示例:直接在 IDEA 中,增加 --spring.profiles.active=dev 到 Program arguments 中。如下图所示:IDEA 配置 - dev

启动 Spring Boot 应用,输出日志如下:

# 省略其它日志...
2020-01-22 19:22:26.038  INFO 13059 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
  • Tomcat 启动在 8081 端口,符合读取 dev 命名空间的 example 配置集。

② 生产环境示例:直接在 IDEA 中,增加 --spring.profiles.active=prod 到 Program arguments 中。如下图所示:IDEA 配置 - prod

启动 Spring Boot 应用,输出日志如下:

# 省略其它日志...
2020-01-22 19:26:33.527  INFO 13162 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8084 (http)
  • Tomcat 启动在 8084 端口,符合读取 prod 命名空间的 example 配置集。

另外,关于 Spring Boot 应用的多环境部署,胖友也可以看看《芋道 Spring Boot 持续交付 Jenkins 入门》文章。

4. 自动刷新配置

示例代码对应仓库:lab-44-nacos-config-demo-auto-refresh

在上面的示例中,我们已经实现从 Nacos 读取配置。那么,在应用已经启动的情况下,如果我们将读取的 Nacos 的配置进行修改时,应用是否会自动刷新本地的配置呢?

如果是我们上面的示例,答案是不会。不过呢,Nacos 提供了上述功能,也就是自动刷新配置。下面,我们来搭建一个自动刷新配置的示例。

4.1 引入依赖

在 pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-44-nacos-config-demo-auto-refresh</artifactId>

    <dependencies>
        <!-- 实现对 SpringMVC 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 实现对 Nacos 作为配置中心的自动化配置 -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-starter</artifactId>
            <version>0.2.4</version>
        </dependency>
    </dependencies>

</project>
  • 引入 spring-boot-starter-web 依赖的原因,稍后我们会编写 API 接口,查看来自 Nacos 配置的最新值。

4.2 创建 Nacos 配置集

在 Nacos 中,创建一个用于测试自动刷新配置的配置集 example-auto-refresh,具体内容如下图:创建 Nacos 配置集

4.3 配置文件

在 application.yml 中,添加 Nacos 配置,如下:

nacos:
  # Nacos 配置中心的配置项,对应 NacosConfigProperties 配置类
  config:
    server-addr: 127.0.0.1:18848 # Nacos 服务器地址
    bootstrap:
      enable: true # 是否开启 Nacos 配置预加载功能。默认为 false。
      log-enable: true # 是否开启 Nacos 支持日志级别的加载时机。默认为 false。
    data-id: example-auto-refresh # 使用的 Nacos 配置集的 dataId。
    type: YAML # 使用的 Nacos 配置集的配置格式。默认为 PROPERTIES。
    group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP。
    namespace: # 使用的 Nacos 的命名空间,默认为 null。
    auto-refresh: true # 是否自动刷新,默认为 false。
  • 「2.2 配置文件」的差异点,是设置 nacos.config.auto-refresh 配置项为 true,开启 Nacos 自动刷新配置的功能。

4.4 TestProperties

在 cn.iocoder.springboot.lab44.nacosdemo.properties 包下,创建 TestProperties 配置类,读取 test 配置项。代码如下:

@Component
@NacosConfigurationProperties(prefix = "", dataId = "${nacos.config.data-id}", type = ConfigType.YAML, autoRefreshed = true)
public class TestProperties {

    /**
     * 测试属性
     */
    private String test;

    // ... 省略 set/get 方法

}
  • 不同于「2.4 OrderProperties」,因为我们要使用自动刷新配置的功能,必须使用 @NacosConfigurationProperties 注解。

这里有一点要注意,nacos.config.auto-refresh 配置项开启的是全局的,必须为 true 时,才能使用自动刷新配置的功能。同时,每个 @NacosConfigurationProperties 或 @NacosValue 注解,也需要设置 autoRefreshed 属性为 true 时,对应的配置项才会自动刷新。

4.5 DemoController

在 cn.iocoder.springboot.lab44.nacosdemo.controller 包下,创建 DemoController 类,提供返回配置的 API 接口。代码如下:

@RestController
@RequestMapping("/demo")
public class DemoController {

//    @Value("${test}")
    @NacosValue(value = "${test}", autoRefreshed = true)
    private String test;

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

    @Autowired
    private TestProperties testProperties;

    @GetMapping("/test_properties")
    public TestProperties testProperties() {
        return testProperties;
    }
    
}
  • /demo/test 接口,测试 @NacosValue 注解。注意,这里为了实现自动刷新配置的功能,我们也无法使用 @Value 注解,而是使用 @NacosValue 替代。同时,设置其 autoRefreshed 属性为 true
  • /demo/test_properties 接口,测试 @NacosConfigurationProperties 注解的 TestProperties 配置类。

4.6 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

4.7 简单测试

启动 Spring Boot 应用,开始我们本轮的测试。

① 分别请求 /demo/test/demo/test_properties 接口,响应结果如下:

# /demo/test 接口
芋艿

# /demo/test_properties 接口
{
    "test": "芋艿"
}

② 修改 Nacos 配置集 example-auto-refresh,将 test 配置项设置为 好帅。如下图所示:修改 Nacos 配置集

并且,我们可以看到控制台会输出大一堆 Nacos 的日志,如下图所示:日志

③ 分别请求 /demo/test/demo/test_properties 接口,响应结果如下:

# /demo/test 接口
好帅

# /demo/test_properties 接口
{
    "test": "好帅"
}
  • 自动刷新配置成功。

4.8 Nacos 配置监听器

通过 @NacosValue 和 @NacosConfigurationProperties 注解,已经能够满足我们绝大多数场景下的自动刷新配置的功能。但是,在一些场景下,我们仍然需要自定义 Nacos 配置监听器,实现对 Nacos 配置的监听,执行自定义的逻辑。

例如说,当数据库连接的配置发生变更时,我们需要通过监听该配置的变更,重新初始化应用中的数据库连接,从而访问到新的数据库地址。

又例如说,当日志级别发生变更时,我们需要通过监听该配置的变更,设置应用中的 Logger 的日志级别,从而后续的日志打印可以根据新的日志级别。

可能这么说,胖友会觉得有点抽象,我们来搭建一个日志级别的示例。

在 cn.iocoder.springboot.lab44.nacosdemo.listener 包下,创建 LoggingSystemConfigListener 类,监听 logging.level 配置项的变更,修改 Logger 的日志级别。代码如下:

@Component
public class LoggingSystemConfigListener {

    /**
     * 日志配置项的前缀
     */
    private static final String LOGGER_TAG = "logging.level.";

    @Resource
    private LoggingSystem loggingSystem;

    @NacosConfigListener(dataId = "${nacos.config.data-id}", type = ConfigType.YAML, timeout = 5000)
    public void onChange(String newLog) throws Exception {
        // <X> 使用 DefaultYamlConfigParse 工具类,解析配置
        Properties properties = new DefaultYamlConfigParse().parse(newLog);
        // <Y> 遍历配置集的每个配置项,判断是否是 logging.level 配置项
        for (Object t : properties.keySet()) {
            String key = String.valueOf(t);
            // 如果是 logging.level 配置项,则设置其对应的日志级别
            if (key.startsWith(LOGGER_TAG)) {
                // 获得日志级别
                String strLevel = properties.getProperty(key, "info");
                LogLevel level = LogLevel.valueOf(strLevel.toUpperCase());
                // 设置日志级别到 LoggingSystem 中
                loggingSystem.setLogLevel(key.replace(LOGGER_TAG, ""), level);
            }
        }
    }

}
  • loggingSystem 属性,是 Spring Boot Logger 日志系统,通过 LoggingSystem 可以进行日志级别的修改。
  • 在 #onChange(String newLog) 方法上,我们添加了 @NacosConfigListener 注解,声明该方法处理指定配置集的配置变化。
  • <X> 处,使用 Nacos 提供的 DefaultYamlConfigParse 解析 YAML 格式的配置。示例如下图所示:DefaultYamlConfigParse
  • <Y> 处,遍历配置集的每个配置项,判断如果是 logging.level 配置项,则设置到 LoggingSystem 中,从而修改日志级别。详细的整个过程,胖友看看艿艿的详细的注释,嘿嘿~

4.9 再次测试

① 在 DemoController 类中,增加如下 API 接口。代码如下:

private Logger logger = LoggerFactory.getLogger(getClass());

@GetMapping("/logger")
public void logger() {
    logger.debug("[logger][测试一下]");
}
  • 如果 DemoController 对应的 Logger 日志级别是 DEBUG 以上,则无法打印出日志。

② 在 Nacos 中,修改测试自动刷新配置的配置集 example-auto-refresh,具体内容如下图:修改 Nacos 配置集

其中,配置内容如下,方便胖友复制:

test: 好帅

logging:
  level:
    cn:
      iocoder:
        springboot:
          lab44:
            nacosdemo:
              controller:
                DemoController: INFO

③ 启动 Spring Boot 应用,开始我们本轮的测试。

④ 请求 /demo/logger 接口,控制台并未打印日志,因为当前日志级别是 INFO。

⑤ 在 Nacos 中,修改测试自动刷新配置的配置集 example-auto-refresh,具体内容如下图:修改 Nacos 配置集 02

⑥ 请求 /demo/logger 接口,控制台打印日志,因为当前日志级别是 DEBUG。日志内容如下:

2020-01-23 14:40:41.484 DEBUG 23501 --- [nio-8080-exec-5] c.i.s.l.n.controller.DemoController      : [logger][测试一下]
  • 符合预期。

🐶 感兴趣的胖友,也可以在 LoggingSystemConfigListener 的监听方法增加断点,嘿嘿~

5. 配置加密

示例代码对应仓库:lab-44-nacos-config-demo-jasypt

考虑到安全性,我们可能最好将配置文件中的敏感信息进行加密。例如说,MySQL 的用户名密码、第三方平台的 Token 令牌等等。不过,Nacos 暂时未内置配置加密的功能。官方文档说明如下:

FROM https://nacos.io/zh-cn/docs/faq.html

Nacos如何对配置进行加密
Nacos 计划在 1.X 版本提供加密的能力,目前还不支持加密,只能靠 sdk 做好了加密再存到 nacos 中。

因此,我们暂时只能在客户端进行配置的加解密。这里,我们继续采用在《芋道 Spring Boot 配置文件入门》「8. 配置加密」小节中使用的 Jasypt

下面,我们来使用 Nacos + Jasypt 搭建一个配置加密的示例。

5.1 引入依赖

在 pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-44-nacos-config-demo-jasypt</artifactId>

    <dependencies>
        <!-- 实现对 SpringMVC 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 实现对 Nacos 作为配置中心的自动化配置 -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-starter</artifactId>
            <version>0.2.4</version>
        </dependency>

        <!-- 实现对 Jasypt 实现自动化配置 -->
        <dependency>
            <groupId>com.github.ulisesbocchio</groupId>
            <artifactId>jasypt-spring-boot-starter</artifactId>
            <version>3.0.2</version>
<!--            <scope>test</scope>-->
        </dependency>

        <!-- 方便等会写单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

5.2 创建 Nacos 配置集

在 Nacos 中,创建一个用于测试配置加密的配置集 example-jasypt,具体内容如下图:创建 Nacos 配置集

这里为了测试简便,我们直接添加加密秘钥 jasypt.encryptor.password 配置项在该 Nacos 配置集中。如果为了安全性更高,实际建议把加密秘钥和配置隔离。不然,如果配置泄露,岂不是可以拿着加密秘钥,直接进行解密。

5.3 配置文件

在 application.yml 中,添加 Nacos 配置,如下:

nacos:
  # Nacos 配置中心的配置项,对应 NacosConfigProperties 配置类
  config:
    server-addr: 127.0.0.1:18848 # Nacos 服务器地址
    bootstrap:
      enable: true # 是否开启 Nacos 配置预加载功能。默认为 false。
      log-enable: true # 是否开启 Nacos 支持日志级别的加载时机。默认为 false。
    data-id: example-jasypt # 使用的 Nacos 配置集的 dataId。
    type: YAML # 使用的 Nacos 配置集的配置格式。默认为 PROPERTIES。
    group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP。
    namespace: # 使用的 Nacos 的命名空间,默认为 null。
    auto-refresh: true # 是否自动刷新,默认为 false。

5.4 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

5.5 简单测试

下面,我们进行下简单测试。

  • 首先,我们会使用 Jasypt 将 demo-application 进行加密,获得加密结果。
  • 然后,将加密结果,赋值到 Nacos 配置集 example-jasypt 的 spring.application.name 配置项。
  • 最后,我们会使用 Jasypt 将 spring.application.name 配置项解密。

创建 JasyptTest 测试类,编写测试代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class JasyptTest {

    @Autowired
    private StringEncryptor encryptor;

    @Test
    public void encode() {
        String applicationName = "demo-application";
        System.out.println(encryptor.encrypt(applicationName));
    }

    @Value("${spring.application.name}")
//    @NacosValue("${spring.application.name}")
    private String applicationName;

    @Test
    public void print() {
        System.out.println(applicationName);
    }

}
  • 首先,执行 #encode() 方法,手动使用 Jasypt 将 demo-application 进行加密,获得加密结果。加密结果如下: 
nFVlMl4ZJ4vJLJ68X4x+a3CIerdaG0488LpZHKyoGxPoJkgemJT/nw==
  • 然后,将加密结果,赋值到 Nacos 配置集 example-jasypt 的 spring.application.name 配置项。如下图所示:修改 Nacos 配置集

  • 最后,执行 #print() 方法,自动使用 Jasypt 将 spring.application.name 配置项解密。解密结果如下:

demo-application
    • 成功正确解密,符合预期。

5.6 补充说明

目前测试下来,在将 Jasypt 集成进来时,Nacos 的「4. 自动配置刷新」功能,竟然失效了。

  • 具体的验证,胖友可以将 jasypt-spring-boot-starter 依赖设置成 <scope>test</scope>,并是使用 DemoController 进行测试。
  • 具体的原因,艿艿暂时没去调试与研究,有了解的胖友,麻烦告知下哟。

如果说,胖友暂时不需要自动配置刷新功能的话,可以考虑选择使用 Jasypt 集成。如果需要的话,那么就等待官方支持吧,暂时不要考虑使用 Jasypt 咧。

6. 监控端点

示例代码对应仓库:lab-44-nacos-config-demo-actuator

《芋道 Spring Boot 监控端点 Actuator 入门》中,我们学习了 Spring Boot Actuator 内置的监控端点。而 Nacos 有个 nacos-config-spring-boot-actuator 子项目,提供了 Nacos 作为 Spring Boot 配置中心时的监控端点。

下面,我们从「4. 自动刷新配置」的 lab-44-nacos-config-demo-auto-refresh 示例项目,复制出 lab-44-nacos-config-demo-actuator 作为本小节的示例。当然,我们还需要将 Actuator 集成到其中。

6.1 引入依赖

修改 pom.xml 文件中,额外引入 Actuator 相关依赖。

<!-- 实现对 Actuator 的自动化配置 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 实现对 Nacos 作为配置中心的 Actuator 的自动化配置 -->
<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>nacos-config-spring-boot-actuator</artifactId>
    <version>0.2.4</version>
</dependency>

6.2 配置文件

修改 application.yaml 配置文件,额外引入 Actuator 相关配置。

management:
  endpoint:
    # Health 端点配置项,对应 HealthProperties 配置类
    health:
      show-details: ALWAYS # 何时显示完整的健康信息。默认为 NEVER 都不展示。可选 WHEN_AUTHORIZED 当经过授权的用户;可选 ALWAYS 总是展示。
  endpoints:
    # Actuator HTTP 配置项,对应 WebEndpointProperties 配置类
    web:
      exposure:
        include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
  • 每个配置项的用途,胖友看下艿艿添加的详细注释。

配置完成后,启动 Spring Boot 应用,我们可以开始测试 Nacos 提供的监控端点了。

6.3 health 端点

health 端点,是 Spring Boot Actuator 内置的健康状态端点。而 Nacos 自定义了 HealthIndicator 实现类 NacosConfigHealthIndicator,获取应用连接 Nacos 的健康状态。

请求 actuator/health 地址,获取健康状态结果如下图:health 端点

6.4 nacos-config 端点

nacos-config 端点,是 Nacos 自定义端点 NacosConfigEndpoint,获得 Nacos 在 Spring Boot 的配置信息。

请求 actuator/nacos-config 地址,获取健康状态结果如下图:nacos-config 端点

7. 配置加载顺序

示例代码对应仓库:lab-44-nacos-config-demo-multi

《芋道 Spring Boot 配置文件入门》「9. 配置加载顺序」小节,我们了解了 Spring Boot 自带的配置加载顺序。本小节,我们来看看来自 Nacos 的配置,在其中的顺序。同时,我们将配置多个 Nacos 配置集,看看它们互相之间的加载顺序。

下面,我们来搭建一个用于测试配置加载顺序的示例。

7.1 引入依赖

在 pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-44-nacos-config-demo-multi</artifactId>

    <dependencies>
        <!-- 实现对 SpringMVC 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 实现对 Nacos 作为配置中心的自动化配置 -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-starter</artifactId>
            <version>0.2.4</version>
        </dependency>
    </dependencies>

</project>

7.2 配置文件

在 application.yml 中,添加 Nacos 配置,如下:

nacos:
  # Nacos 配置中心的配置项,对应 NacosConfigProperties 配置类
  config:
    server-addr: 127.0.0.1:18848 # Nacos 服务器地址
    bootstrap:
      enable: true # 是否开启 Nacos 配置预加载功能。默认为 false。
      log-enable: true # 是否开启 Nacos 支持日志级别的加载时机。默认为 false。
    data-id: example-multi-01 # 使用的 Nacos 配置集的 dataId。
#    data-ids: example-multi-02
    type: YAML # 使用的 Nacos 配置集的配置格式。默认为 PROPERTIES。
    group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP。
    namespace: # 使用的 Nacos 的命名空间,默认为 null。
    auto-refresh: true # 是否自动刷新,默认为 false。
    ext-config:
      - server-addr: 127.0.0.1:18848 # Nacos 服务器地址
#        data-id: example-multi-11 # 使用的 Nacos 配置集的 dataId。
        data-ids: example-multi-11, example-multi-12
        type: YAML # 使用的 Nacos 配置集的配置格式。默认为 PROPERTIES。
        group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP。
        namespace: # 使用的 Nacos 的命名空间,默认为 null。
        auto-refresh: true # 是否自动刷新,默认为 false。
#      - # 这里,可以继续添加。
  • 在 nacos.config 配置项下,可以通过 data-id 和 data-ids 来设置使用的 Nacos 配置集。不过要注意,这两者只能二选一。
  • 在 nacos.config.ext-config 配置项下,它是 Config 数组,可以配置多个配置集。实际上,Config 的属性和 nacos.config 是基本类似的,从艿艿这里给出来的示例,是不是已经可以发现啦。不过要注意,nacos.config 配置项下的优先级高于 nacos.config.ext-config

这里,Nacos 配置集 example-multi-01example-multi-11example-multi-12 需要创建下,具体的配置内容随意哈。

7.3 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

@SpringBootApplication
// @NacosPropertySource(dataId = "example", type = ConfigType.YAML)
public class Application {

    public static void main(String[] args) {
        // 启动 Spring Boot 应用
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

        // 查看 Environment
        Environment environment = context.getEnvironment();
        System.out.println(environment);
    }

}

在代码中,我们去获取了 Spring Environment 对象,因为我们要从其中获取到 PropertySource 配置来源。DEBUG 运行 Application,并记得在 System.out.println(environment); 代码块打一个断点,可以看到如下图的调试信息:调试信息

  • 每一个 Nacos 配置集,对应一个 PropertySource 对象,并且 nacos.config 配置项下的优先级高于 nacos.config.ext-config
  • 所有 Nacos 配置集的 PropertySource 对象,排在 application.yaml 配置文件的 PropertySource 对象后面,也就是优先级最低。
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值