轻松上手 Nacos 配置中心:配置共享、热更新与动态路由详解
在微服务架构中,网关通常承担着路由转发的核心职责,因此其中配置了大量的路由规则。然而,每当新增一个业务微服务时,往往需要手动修改网关配置并重启整个网关服务才能生效。类似的问题也广泛存在于其他微服务中——诸如数据库连接信息、限流阈值、功能开关等配置项不仅存在重复定义,而且一旦发生变更,同样需要重启服务才能加载新配置。这种静态配置方式严重制约了系统的灵活性和可维护性。
为解决上述痛点,亟需引入一个集中化、支持动态热更新的配置管理工具。通过统一管理所有微服务的配置,并在不重启服务的前提下实时推送配置变更,从而显著提升系统的运维效率与稳定性。Nacos 配置中心正是为此类场景而生的理想解决方案。
以下配置都是基于 Nacos 进行配置的,如果对 Nacos 不太了解可以翻看我前面的作品:
1. 配置共享
1. 抽取公共配置文件
抽取配置文件以下面配置文件为例
spring:
datasource:
url: jdbc:mysql://192.168.150.128:project.db.port:3306/project.db.database?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
global-config:
db-config:
update-strategy: not_null
id-type: auto
以上依赖为数据库jdbc与mybatis-plus的相关依赖,几乎每个模块都需要使用,因此可以将其抽取出来进行复用。
2. 添加公共配置
打开 nacos 网站,点击右侧配置管理

点击右上角的加号,创建一个新的配置。

Data ID 是 Nacos 中每条配置的唯一标识符。在微服务项目中,若要引用某个配置文件(如公共配置或环境特定配置),必须通过其对应的 Data ID 进行关联和加载。因此,Data ID 不仅用于区分不同的配置内容,也是客户端从 Nacos 配置中心拉取指定配置的关键依据。
最终效果:

代码:
spring:
datasource:
url: jdbc:mysql://${project.db.host:192.168.150.128}:${project.db.port:3306}/${project.db.database}?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${project.db.un:root}
password: ${project.db.pw:123}
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
global-config:
db-config:
update-strategy: not_null
id-type: auto
其中,${project.db.host:192.168.150.128} 是 Spring Boot 支持的占位符语法,表示从外部配置(如配置中心、环境变量或 application.yml)中读取 project.db.host 的值;若未显式指定该变量,则自动使用冒号后的默认值 192.168.150.128。
通过这种方式,可以在不同环境(开发、测试、生产)或不同微服务中灵活覆盖这些配置项,而无需修改公共配置文件本身。这不仅减少了重复配置,也增强了系统的可移植性和运维灵活性,尤其适用于结合 Nacos 等配置中心实现动态、集中化管理的场景。
3. 拉取公共配置
在将数据库相关配置抽取到 Nacos 后,本地项目中的 application.yml(或 application.yaml)中可删除重复的数据库配置,转而通过引用 Nacos 中已配置好的共享配置文件来统一管理。例如:
spring:
application:
name: user-service # 服务名称
profiles:
active: dev
cloud:
nacos:
server-addr: 192.168.150.128 # nacos地址
config:
file-extension: yaml # 文件后缀名
shared-configs: # 共享配置
- dataId: shared-jdbc.yaml # 共享mybatis配置
然而,启动项目时可能会遇到“缺少数据库配置”的错误。原因如下:
Nacos 配置的加载发生在 Spring Cloud 的引导(Bootstrap)阶段,该阶段早于 Spring Boot 应用上下文(ApplicationContext)的初始化。而 application.yaml 是在 Spring Boot 上下文启动时才被加载的——这意味着,在引导阶段,应用尚未读取 application.yaml,自然无法获取其中定义的 Nacos 地址,也就无法从 Nacos 拉取配置,最终导致数据库等关键配置缺失。
1. bootstrap.yaml
SpringCloud 在初始化上下文的时候会先读取一个名为 bootstrap.yaml(或者 bootstrap.properties) 的文件,如果我们将 nacos 地址配置到 bootstrap.yaml 中,那么在项目引导阶段就可以读取 nacos 中的配置了。
2. 引入依赖
要启用 bootstrap.yaml 的加载机制,需在项目中添加以下两个依赖:
<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>
说明:从 Spring Cloud 2020.0.0(即 Ilford 版本)开始,Bootstrap 上下文默认被禁用,必须显式引入 spring-cloud-starter-bootstrap 才能启用。
3. 配置 bootstrap 文件
将 Nacos 相关配置从 application.yaml 移至 bootstrap.yaml,示例如下:
spring:
application:
name: user-service
profiles:
active: dev
cloud:
nacos:
server-addr: 192.168.150.128
config:
file-extension: yaml
shared-configs:
- dataId: shared-jdbc.yaml
完成上述配置后,项目在启动时将首先通过 bootstrap.yaml 连接 Nacos,并成功拉取 shared-jdbc.yaml 等共享配置,从而避免因配置缺失导致的启动失败。
2. 热更新
在实际业务开发中,常常存在一些需要频繁调整的参数(如限流阈值、功能开关、业务上限等)。即使将这些参数抽取到配置文件中,在应用部署上线后若需修改,传统方式仍需重启服务,严重影响运维效率和系统可用性。
Nacos 配置中心提供了 配置热更新(Hot Reload)能力:当配置发生变化时,无需重启服务,应用即可实时感知并加载最新值,从而实现灵活、高效的动态配置管理。
场景示例:
假设当前有一个用户(user-service)业务模块,允许用户创建执行任务,但对每个用户可创建的任务数量设有上限(例如 maxMission)。该上限可能因运营策略或系统负载而频繁调整。为提升灵活性,可将此参数托管至 Nacos,并支持运行时动态修改。
1. 配置热更新参数
按照上面公共配置文件的思路:首先应该在 nacos 中配置内容,然后在 bootstrap.yaml 中拉取配置,最后在项目中使用该参数即可。
但是 Spring Cloud Alibaba 与 Nacos 集成时,在服务启动阶段会自动从 Nacos 拉取一个默认配置,其 Data ID 命名规则如下:
${spring.application.name}-${spring.profiles.active}.${file-extension}
参数含义:
- ${spring.application.name}:服务名称(如 user-service)
- ${spring.profiles.active}:当前激活的环境 profile(如 dev、prod),可省略
- ${file-extension}:配置格式后缀(如 yaml 或 properties)
这意味着:只要在 Nacos 中创建一个符合上述命名规则的配置(例如 user-service-dev.yaml),服务在启动时就会自动加载该配置内容,无需在代码或配置文件中显式声明拉取逻辑。
示例:
若 spring.application.name=user-service,spring.profiles.active=dev,file-extension = yaml,
则服务启动时会自动尝试加载 Data ID 为 user-service-dev.yaml 的配置,dev 可以省略,那么就可以写成:user-service.yaml
配置后内容如下:

2. 使用参数
通过 @ConfigurationProperties 绑定配置属性,并配合 @RefreshScope 实现热更新:
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Data
@Component
@RefreshScope // 启用配置热更新
@ConfigurationProperties(prefix = "project.user")
public class TaskProperties {
private Integer maxMission;
}
- @ConfigurationProperties(prefix = "project.user"):绑定 project.user.maxMission 配置项;
- @RefreshScope:必须添加,使该 Bean 在 Nacos 配置变更时能重新注入最新值;
- @Component:注册为 Spring Bean,便于注入使用。
3. 动态生效
部署上线后,若需调整任务上限,只需在 Nacos 控制台修改 user-service.yaml 中的 maxMission 值并点击“发布”,应用将在几秒内自动应用新配置,无需重启服务。
3. 动态获取路由
在微服务架构中,API 网关(如 Spring Cloud Gateway)通常负责统一的路由转发。随着业务迭代,新增或调整微服务时,往往需要修改网关中的路由配置。若每次变更都需重启网关服务,将严重影响系统可用性。
为此,可将路由配置抽取至 Nacos 配置中心,并通过监听机制实现动态加载与热更新,做到“配置即生效”,无需重启网关。
对网关路由相关内容不太了解的可以查看前面文章:
1. 抽取配置文件
原始网关路由配置(YAML 格式)示例如下:
spring:
cloud:
gateway:
routes:
- id: test
uri: lb://test-service
predicates:
- Path=/test/**
- id: user
uri: lb://user-service
predicates:
- Path=/user/**
- id: item
uri: lb://item-service
predicates:
- Path=/item/**
为便于程序解析和动态更新,建议将其转换为 JSON 格式,并存入 Nacos。
- Data ID:gateway-routes.json
- Group:保持默认 DEFAULT_GROUP
对应的 JSON 配置内容如下(与 YAML 语义等价):
[
{
"id": "test",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/test/**"}
}],
"filters": [],
"uri": "lb://test-service"
},
{
"id": "user",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/user/**"}
}],
"filters": [],
"uri": "lb://user-service"
},
{
"id": "item",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/item/**"}
}],
"filters": [],
"uri": "lb://item-service"
}
]
说明:Spring Cloud Gateway 内部使用
_genkey_0作为Path谓词的参数键名,这是其 Predicate 工厂的默认行为。
2. 监听配置文件
通过 NacosConfigManager 监听指定 Data ID 的配置变化,并在变更时触发路由更新逻辑。
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {
private final RouteDefinitionWriter routeDefinitionWriter;
private final NacosConfigManager nacosConfigManager;
private static final String DATA_ID = "gateway-routes.json";
private static final String GROUP = "DEFAULT_GROUP";
// 用于记录当前已加载的路由 ID,便于后续删除
private final Set<String> currentRouteIds = new HashSet<>();
/**
* Bean 初始化完成后,注册 Nacos 配置监听器
*/
@PostConstruct
public void initRouteConfigListener() throws NacosException {
ConfigService configService = nacosConfigManager.getConfigService();
// 首次拉取配置并注册监听器
String initialConfig = configService.getConfigAndSignListener(
DATA_ID, GROUP, 5000, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.info("监听到 Nacos 路由配置更新:{}", configInfo);
updateRoutes(configInfo);
}
@Override
public Executor getExecutor() {
return null; // 使用默认线程池
}
}
);
// 初始化时加载一次路由
if (initialConfig != null) {
updateRoutes(initialConfig);
}
}
/**
* 根据新的配置信息更新网关路由
*/
private void updateRoutes(String configJson) {
log.info("开始更新网关路由配置...");
// 解析 JSON 为 RouteDefinition 列表
List<RouteDefinition> newRoutes = JSONUtil.toList(configJson, RouteDefinition.class);
// 1. 删除旧路由
for (String routeId : currentRouteIds) {
routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
log.debug("已删除路由:{}", routeId);
}
currentRouteIds.clear();
// 2. 添加新路由
for (RouteDefinition route : newRoutes) {
routeDefinitionWriter.save(Mono.just(route)).subscribe();
currentRouteIds.add(route.getId());
log.info("已添加路由:{}", route.getId());
}
log.info("网关路由更新完成,共加载 {} 条路由", newRoutes.size());
}
}
关键点说明
| 组件 | 作用 |
|---|---|
| @PostConstruct | 在 Bean 初始化完成后自动注册监听器,确保服务启动时即可加载初始路由 |
| NacosConfigManager | Nacos 提供的配置客户端,用于获取和监听远程配置 |
| RouteDefinitionWriter | Spring Cloud Gateway 提供的路由写入接口,支持动态增删路由 |
| currentRouteIds | 缓存当前已加载的路由 ID,避免重复或残留路由 |
| JSONUtil.toList(...) | 假设使用 Hutool 工具类;也可替换为 Jackson 或 FastJSON 实现 |
注意:由于路由更新涉及异步操作(Mono.subscribe()),在高并发或频繁变更场景下,建议增加防抖(debounce)或加锁机制,避免并发冲突。
3. 效果验证
- 启动网关服务后,自动从 Nacos 加载 gateway-routes.json 并注册路由;
- 在 Nacos 控制台修改该配置并发布,网关日志将输出“监听到配置更新”,并自动刷新路由;
- 无需重启网关,新路由立即生效。
4. 总结
通过将 Spring Cloud Gateway 的路由配置托管至 Nacos,并结合 RouteDefinitionWriter 与 Nacos 监听机制,可实现完全动态、零停机的路由管理。这不仅提升了运维效率,也为灰度发布、蓝绿部署等高级场景提供了基础支持。
更多推荐



所有评论(0)