集成Nacos实现配置动态刷新

通过前文的讲解,读者应该掌握了在应用程序中整合 Nacos 配置中心并从 Nacos 配置中心获取配置项的方法,本节将通过实际的编码来实现整合 Nacos 配置中心后非常实用的功能:配置动态刷新和多配置文件读取。

实现业务开关

业务开关是一种用于控制系统功能的设备,通过开启或关闭来影响系统的行为。配置动态刷新的一个非常实用的功能就是控制相关功能点的开启或关闭。Nacos 可以通过可视化界面或 API 动态修改配置项的值,从而实现业务开关的开启或关闭。

先在 Nacos Server 中创建一个配置项,用于存储业务开关的状态值。

然后在业务代码中使用 Nacos API 读取该开关配置项的值,并在运行时判断是否启用业务逻辑。

接下来,笔者将结合实际的编码来实现对某个业务功能的开关控制。

比如,项目中存在某个功能模块,但是这个功能并不会一直开启,而是在部分时间开启,此时就可以借助 Nacos 配置中心的配置动态刷新功能来实现这个业务开关。

本节将继续在 spring-cloud-alibaba-nacos-config-demo 项目的基础上开发和讲解。在 ltd.newbee.cloud.api 包中新建 ConfigTestController 类,并新增如下代码:

package ltd.newbee.cloud.api;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RefreshScope //配置动态刷新
public class ConfigTestController {

    //在配置中心输入的配置项(默认为false)
    @Value("${activitySwitch.val:false}")
    private Boolean activitySwitch;

    @GetMapping("/configTest")
    public String configTest () {
        if (activitySwitch) {
            return "活动页面渲染所需数据";
        } else {
            return "活动未开启";
        }
    }
}

在代码中定义了一个布尔值变量 activitySwitch,并使用 @Value 注解读取该变量,由于此时已经集成了 Nacos 配置中心,因此会读取 Nacos 配置中心里所配置的内容。activitySwitch 变量的默认值为 false,即使无法正确通过 Nacos Server 获取该配置项,应用程序也可以使用默认值完成启动加载。

之后,创建了一个 configTest() 方法,其业务逻辑是根据 activitySwitch 变量的值来控制是否返回活动页面所需的数据,如果 activitySwitch 变量值为 true,则返回 “活动页面渲染所需数据”,否则返回 “活动未开启”。

另外,实现配置动态刷新的重点是 @RefreshScope 注解,在类上声明了该注解,Nacos 配置中心里的属性变动就会动态同步到当前类的变量中。如果不添加 @RefreshScope 注解,即使监听到属性变更,变量的值也不会被刷新。

编码完成后进行功能验证。打开浏览器并进入 Nacos 控制台页面,在 newbee-cloud-config-service-dev.properties 中增加一行配置(如图 6-34 所示):

#activitySwitch开关值
activitySwitch.val=false

添加完成后,单击 “发布” 按钮即可。

image 2025 04 16 14 33 15 188
Figure 1. 图6-34 在 Nacos 控制台中增加一行配置

下面启动 nacos-config-demo 项目(需保证 Nacos Server 和 MySQL Server 已经正常运行)。如果一切正常,则打开浏览器,输入如下请求地址:

http://localhost:8094/configTest

浏览器输出的内容如下:

活动未开启

再次进入 Nacos 控制台页面,修改 newbee-cloud-config-service-dev.properties 配置中的 activitySwitch.val 值为 true,修改前后的内容对比如图 6-35 所示。修改完成后,单击 “确认发布” 按钮。

image 2025 04 16 14 35 18 828
Figure 2. 图6-35 配置修改前后的内容对比

此时,观察项目的启动日志,多了一行内容,日志如下:

image 2025 04 16 14 35 41 518

这行日志说明配置项 activitySwitch.val 值的更改已被程序实时监听到,再次在浏览器中访问如下请求地址:

http://localhost:8094/configTest

此时,浏览器输出的内容如下:

活动页面渲染所需数据

验证通过,程序并未重新启动就能够实时读取配置中心里的最新数据,说明配置动态刷新功能开发完成。

配置动态刷新功能的好处及应用场景

配置动态刷新功能可以给应用程序带来如下好处。

  1. 更灵活的控制:可以在不重启应用程序的情况下动态更改配置。

  2. 更快的问题修复:可以在发现问题后立即修复配置,而不是等到重启应用程序时。

  3. 更高的可用性:可以避免因重启应用程序导致的服务中断。

  4. 更好的灵活性:可以根据需求随时调整配置。

总结起来就是可以让开发人员在不重启应用程序的前提下更新配置信息,给系统应用带来更多的灵活性。常见的应用场景有业务开关、业务规则实时更新、灰度发布,以及动态刷新数据源、动态刷新日志级别等非常实用的场景。

不过,千万不要不加控制地使用动态刷新功能,也不要刻意去追求配置的灵活性,这些都是对动态刷新功能的滥用。比如,引入配置中心后为了追求所谓的灵活性而在代码中添加了过多的“业务开关”,乍一看灵活了很多,但是这样会极大地增加维护成本,甚至后来者根本不清楚甚至看不懂之前遗留的一些“业务开关”。一套服务代码里有几十个甚至几百个所谓的“业务开关”,代码理解起来费劲,修改起来又担心改错,如果开发和维护变成这个样子,为了追求灵活性而做的一些事情反而给项目带来掣肘,就是典型的南辕北辙了。

另外,某些动态刷新的场景需要进行二次编码,并不是仅改几行配置代码就能完成的,像动态刷新数据源、动态刷新日志级别就需要自行实现监听逻辑进行二次开发。以动态刷新数据源为例,如果在 Nacos 控制台中修改了数据源的地址——spring.datasource.url 配置项,应用程序也能够实时监听到,系统运行日志如下:

image 2025 04 16 14 37 13 586

不过,虽然 spring.datasource.url 配置项刷新了,但是应用程序中连接的依然是原来的数据库。也就是说,仅仅修改配置项不会使数据源刷新生效,没生效的原因并不是 spring.datasource.url 配置项没更新,该配置项更新了,应用程序中对应的变量值也更新了,在项目中读取是能够读到最新的参数值的。但是,因为数据源对象及相关的代理对象在项目启动期间已经生成,这里虽然读到了最新的 spring.datasource.url 配置项,但是并不会重新执行数据源对象的构建操作。看到这里读者应该明白了,spring.datasource.url 会随着 Nacos 配置中心里的更改而更新,但是数据源对象(如 HikariDataSource 类型的 Bean)是不会随着 spring.datasource.url 配置项的更改而更新的,这是两回事。

想要动态刷新数据源或日志级别,不是简简单单读取一个配置项更新就能完成的。此时需要开发人员在应用程序中做额外的编码,在监听到相关配置项更新时,重新构造数据源对象或日志工厂对象,再放到 IoC 容器中,这样才能完成数据源对象/日志级别的刷新,这种操作基本上属于热更新了。

数据源动态刷新这种需求其实并不多见,因此本书就不再赘述了,读者实在有类似的需求,可以看一看类似的教程。另外,对于不同的数据源对象刷新,编码也是不同的,如常用的 Hikari 数据源和 Druid 数据源,这些都能够搜索到,可以使用如下关键字进行搜索,如 “整合 Nacos 动态刷新日志级别”、“整合 Nacos 动态刷新数据源”。