文章目录
-
- [一、Nacos 配置中心概述](#一、Nacos 配置中心概述)
-
- [1.1 为什么需要配置中心?](#1.1 为什么需要配置中心?)
- [1.2 Nacos 配置中心架构](#1.2 Nacos 配置中心架构)
- [1.3 核心特性对比](#1.3 核心特性对比)
- 二、快速入门:搭建第一个配置中心
-
- [2.1 环境准备](#2.1 环境准备)
- [2.2 Nacos Server 安装部署](#2.2 Nacos Server 安装部署)
-
- [方式一:Docker 快速部署(推荐)](#方式一:Docker 快速部署(推荐))
- 方式二:二进制包安装
- 方式三:源码编译安装
- [2.3 访问 Nacos 控制台](#2.3 访问 Nacos 控制台)
- [2.4 创建第一个配置](#2.4 创建第一个配置)
- 三、核心原理深度解析
-
- [3.1 配置加载流程](#3.1 配置加载流程)
- [3.2 配置文件命名规则](#3.2 配置文件命名规则)
- [3.3 动态刷新原理](#3.3 动态刷新原理)
- 四、高级特性全掌握
-
- [4.1 多环境配置隔离方案](#4.1 多环境配置隔离方案)
- [4.2 配置分组与共享配置](#4.2 配置分组与共享配置)
- [4.3 配置监听器编程实现](#4.3 配置监听器编程实现)
- [4.4 配置加密与敏感信息保护](#4.4 配置加密与敏感信息保护)
- [4.5 灰度发布(Beta发布)实战](#4.5 灰度发布(Beta发布)实战)
- 五、生产级实践方案
-
- [5.1 Nacos 集群部署架构](#5.1 Nacos 集群部署架构)
- [5.2 集群配置文件](#5.2 集群配置文件)
- [5.3 客户端连接集群配置](#5.3 客户端连接集群配置)
- [5.4 配置变更审批流程](#5.4 配置变更审批流程)
- [5.5 监控与告警](#5.5 监控与告警)
- 六、完整示例项目
-
- [6.1 项目结构](#6.1 项目结构)
- [6.2 pom.xml 完整配置](#6.2 pom.xml 完整配置)
- [6.3 配置类与属性绑定](#6.3 配置类与属性绑定)
- [6.4 配置控制器](#6.4 配置控制器)
- [6.5 Bootstrap 配置](#6.5 Bootstrap 配置)
- [6.6 Actuator 监控配置](#6.6 Actuator 监控配置)
- 七、常见问题与解决方案
-
- [7.1 问题诊断流程图](#7.1 问题诊断流程图)
- [7.2 问题排查清单](#7.2 问题排查清单)
- [7.3 常用排查命令](#7.3 常用排查命令)
- [八、 总结与学习路径](#八、 总结与学习路径)
- 参考资源
一文精通 Nacos 配置中心的核心原理、最佳实践与生产落地方案
一、Nacos 配置中心概述
1.1 为什么需要配置中心?
传统配置管理
配置散落在各应用
修改需重启服务
多环境配置重复
配置变更无法追溯
配置中心模式
配置集中管理
动态热更新
多环境/多租户隔离
版本控制与回滚
❌ 痛点明显
✅ 优雅解决
1.2 Nacos 配置中心架构
管理控制台
存储层
服务端层
SDK层
客户端层
Spring Boot应用1
Spring Boot应用2
Spring Boot应用3
Nacos Client SDK
长轮询监听配置变更
Nacos Server节点1
Nacos Server节点2
Nacos Server节点3
MySQL/Derby
持久化配置数据
Nacos Console
配置CRUD界面
1.3 核心特性对比
| 特性 | Nacos | Spring Cloud Config | Apollo |
|---|---|---|---|
| 动态刷新 | ✅ 支持 | ✅ 支持(需配合Bus) | ✅ 支持 |
| 管理界面 | ✅ 原生提供 | ❌ 需自行开发 | ✅ 原生提供 |
| 多环境隔离 | ✅ Namespace | ✅ Profile | ✅ Namespace/AppId |
| 灰度发布 | ✅ Beta发布 | ❌ 不支持 | ✅ 灰度规则 |
| 配置格式 | YAML/Properties/JSON/XML | YAML/Properties | YAML/Properties/JSON/XML/TXT |
| 学习成本 | 🟢 低 | 🟡 中 | 🟡 中 |
| 社区活跃度 | 🟢 高 | 🟡 中 | 🟡 中 |
二、快速入门:搭建第一个配置中心
2.1 环境准备
bash
# 检查 Java 版本(要求 JDK 8+)
java -version
# 检查 Maven 版本(建议 3.6+)
mvn -version
2.2 Nacos Server 安装部署
方式一:Docker 快速部署(推荐)
bash
# 单机模式启动
docker run -d \
--name nacos-standalone \
-e MODE=standalone \
-p 8848:8848 \
-p 9848:9848 \
nacos/nacos-server:v2.3.0
# 查看日志
docker logs -f nacos-standalone
方式二:二进制包安装
bash
# 下载 Nacos
cd /opt
wget https://github.com/alibaba/nacos/releases/download/2.3.0/nacos-server-2.3.0.tar.gz
tar -zxvf nacos-server-2.3.0.tar.gz
cd nacos/bin
# 单机模式启动
./startup.sh -m standalone
# 查看启动日志
tail -f ../logs/start.out
方式三:源码编译安装
bash
# 克隆源码
git clone https://github.com/alibaba/nacos.git
cd nacos
# 编译打包(跳过测试)
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
# 编译产物位于
# distribution/target/nacos-server-2.3.0.tar.gz
2.3 访问 Nacos 控制台
访问地址:http://localhost:8848/nacos
默认账号:nacos / nacos
首次登录后建议立即修改密码:
bash
# 进入容器修改(Docker 方式)
docker exec -it nacos-standalone bash
cd /home/nacos/conf
# 编辑 application.properties 修改数据库连接或配置
2.4 创建第一个配置
登录 Nacos 控制台
点击 配置管理 → 配置列表
点击 + 新建配置
填写配置信息
Data ID: example-dev.yaml
Group: DEFAULT_GROUP
配置格式: YAML
配置内容
点击发布
配置生效成功
配置示例内容:
yaml
# 应用基础配置
app:
name: example-service
version: 1.0.0
env: dev
# 服务端口配置
server:
port: 8080
# 数据源配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/example_db?useSSL=false&serverTimezone=UTC
username: root
password: ENC(encrypted_password_here)
# 业务配置
business:
max-retry: 3
timeout: 5000
feature-switch:
enable-cache: true
enable-new-algo: false
三、核心原理深度解析
3.1 配置加载流程
Spring PropertySource Nacos Server Nacos Config Client BootstrapContext Spring Boot应用 Spring PropertySource Nacos Server Nacos Config Client BootstrapContext Spring Boot应用 启动加载bootstrap上下文 初始化NacosConfigService 拉取配置(dataId, group, namespace) 返回配置内容 解析配置内容 创建NacosPropertySource 加入Environment 配置注入Bean 应用启动完成 启动长轮询监听配置变更
3.2 配置文件命名规则
完整Data ID格式:
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
示例分解:
┌─────────────────┬────┬────────┬────────────────────────┐
│ user-service │ - │ dev │ .yaml │
│ 应用名称 │分隔符│ 环境标识 │ 文件扩展名 │
└─────────────────┴────┴────────┴────────────────────────┘
优先级(高→低):
1. user-service-dev.yaml ← 具体环境配置
2. user-service.yaml ← 通用配置
3. shared-configs 配置 ← 共享配置
4. extension-configs 配置 ← 扩展配置
3.3 动态刷新原理
注解刷新机制
配置更新主流程
控制台修改
Server保存
MD5指纹变更
长轮询检测
收到通知
拉取新配置
更新PropertySource
触发Bean刷新
发布变更事件
无感感知
原始Bean
代理包装
清空缓存
重创建Bean
注入新值
四、高级特性全掌握
4.1 多环境配置隔离方案
方案三:组合方式(推荐)
Namespace隔离环境
Profile隔离场景
完全物理隔离
方案二:Namespace方式
生产空间
隔离配置+注册中心
测试空间
隔离配置+注册中心
开发空间
隔离配置+注册中心
方案一:Profile方式
生产环境
Data ID: app-prod.yaml
测试环境
Data ID: app-test.yaml
开发环境
Data ID: app-dev.yaml
方案配置示例
方案一:Profile 方式
yaml
# application.yml
spring:
profiles:
active: ${ENV:dev} # 通过环境变量指定
application:
name: order-service
cloud:
nacos:
config:
server-addr: ${NACOS_ADDR:127.0.0.1:8848}
file-extension: yaml
group: DEFAULT_GROUP
namespace: public # 共用命名空间
# 环境配置加载
shared-configs:
- data-id: common-${spring.profiles.active}.yaml
group: COMMON_GROUP
refresh: true
方案二:Namespace 方式
yaml
# application-dev.yml(开发环境)
spring:
profiles:
active: dev
cloud:
nacos:
config:
namespace: dev-namespace-id-here # 开发空间ID
group: DEV_GROUP
# application-prod.yml(生产环境)
spring:
profiles:
active: prod
cloud:
nacos:
config:
namespace: prod-namespace-id-here # 生产空间ID
group: PROD_GROUP
4.2 配置分组与共享配置
yaml
spring:
application:
name: payment-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
group: PAYMENT_GROUP # 业务分组
# 共享配置 - 所有微服务共用
shared-configs:
- data-id: common-redis.yaml
group: COMMON_GROUP
refresh: true
- data-id: common-mq.yaml
group: COMMON_GROUP
refresh: true
# 扩展配置 - 当前服务特有
extension-configs:
- data-id: payment-channel.yaml
group: PAYMENT_GROUP
refresh: true
- data-id: payment-risk.yaml
group: RISK_GROUP
refresh: true
配置层次结构
应用主配置
payment-service.yaml
扩展配置1
payment-channel.yaml
扩展配置2
payment-risk.yaml
共享配置1
common-redis.yaml
共享配置2
common-mq.yaml
最终 Environment
Bean 注入
4.3 配置监听器编程实现
示例一:注解式监听器
java
package com.example.nacos.listener;
import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 配置变更监听器 - 注解方式
*/
@Slf4j
@Component
public class ConfigChangeListener {
@NacosConfigListener(dataId = "payment-service.yaml", groupId = "PAYMENT_GROUP")
public void onPaymentConfigChange(String newConfig) {
log.info("====== 检测到配置变更 ======");
log.info("配置内容:\n{}", newConfig);
log.info("==========================");
// 这里可以添加自定义处理逻辑
handleConfigChange(newConfig);
}
@NacosConfigListener(dataId = "common-redis.yaml", timeout = 5000)
public void onRedisConfigChange(String newConfig) {
log.info("Redis 配置已更新,准备刷新连接池...");
// 刷新 Redis 连接池
refreshRedisPool(newConfig);
}
private void handleConfigChange(String config) {
// 自定义业务逻辑
// 例如:发送告警通知、记录变更日志等
}
private void refreshRedisPool(String config) {
// 解析配置并刷新连接池
}
}
示例二:编程式监听器(更灵活)
java
package com.example.nacos.listener;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 配置变更监听器 - 编程方式
*/
@Slf4j
@Component
public class ProgrammaticConfigListener {
@Value("${spring.cloud.nacos.config.server-addr}")
private String serverAddr;
@Value("${spring.application.name}")
private String appName;
private ConfigService configService;
private ExecutorService executorService;
@PostConstruct
public void init() throws NacosException {
// 初始化 Nacos ConfigService
configService = NacosFactory.createConfigService(serverAddr);
executorService = Executors.newSingleThreadExecutor();
// 添加多个配置监听器
addListener("payment-service.yaml", "PAYMENT_GROUP", this::handlePaymentConfig);
addListener("common-redis.yaml", "COMMON_GROUP", this::handleRedisConfig);
addListener("feature-toggle.yaml", "DEFAULT_GROUP", this::handleFeatureToggle);
}
/**
* 添加配置监听器
*/
private void addListener(String dataId, String group, ConfigChangeHandler handler)
throws NacosException {
configService.addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
return executorService;
}
@Override
public void receiveConfigInfo(String configInfo) {
log.info("配置变更: dataId={}, group={}", dataId, group);
handler.handle(configInfo);
}
});
log.info("已添加配置监听器: dataId={}, group={}", dataId, group);
}
private void handlePaymentConfig(String config) {
log.info("处理支付服务配置变更...");
// 具体处理逻辑
}
private void handleRedisConfig(String config) {
log.info("处理 Redis 配置变更...");
// 刷新 Redis 连接池
}
private void handleFeatureToggle(String config) {
log.info("处理功能开关配置变更...");
// 通知相关模块更新开关状态
}
@PreDestroy
public void destroy() {
if (executorService != null) {
executorService.shutdown();
}
}
@FunctionalInterface
private interface ConfigChangeHandler {
void handle(String config);
}
}
4.4 配置加密与敏感信息保护
java
package com.example.nacos.encryption;
import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Jasypt 配置加密
*/
@Configuration
@EnableEncryptableProperties
public class JasyptConfig {
@Bean("jasyptStringEncryptor")
public PooledPBEStringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
// 从环境变量读取密钥(更安全)
config.setPassword(System.getenv("JASYPT_ENCRYPTOR_PASSWORD"));
// 或使用固定密钥(不推荐生产环境)
// config.setPassword("my-secret-key");
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor;
}
}
加密配置使用:
yaml
# Nacos 中的配置
datasource:
url: jdbc:mysql://prod-db.example.com:3306/app_db
username: app_user
password: ENC(3GzL1vX4R2q5P9y7K8w3S6t1N0m4B7c=) # 加密后的密码
加密工具类:
java
package com.example.nacos.util;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
/**
* Jasypt 加密工具类
*/
public class JasyptUtil {
private static final String PASSWORD = "my-secret-key"; // 替换为实际密钥
public static void main(String[] args) {
String plainText = "MySecretPassword123";
String encrypted = encrypt(plainText);
String decrypted = decrypt(encrypted);
System.out.println("原文: " + plainText);
System.out.println("加密: " + encrypted);
System.out.println("解密: " + decrypted);
System.out.println("验证: " + plainText.equals(decrypted));
}
public static String encrypt(String plainText) {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(PASSWORD);
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor.encrypt(plainText);
}
public static String decrypt(String encryptedText) {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(PASSWORD);
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor.decrypt(encryptedText);
}
}
4.5 灰度发布(Beta发布)实战
灰度范围
灰度实例
IP: 192.168.1.10
普通实例
继续使用旧配置
灰度发布流程
验证通过
发现问题
编辑配置
勾选 Beta 发布
指定灰度 IP 列表
点击发布
验证灰度实例
全量发布
回滚/调整
灰度发布操作步骤:
bash
# 灰度 IP 配置示例
灰度 IP:
- 192.168.1.10 # 灰度实例1
- 192.168.1.11 # 灰度实例2
- 10.0.0.5 # 灰度实例3
通过代码获取当前实例 IP:
java
package com.example.nacos.util;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* IP 工具类
*/
@Slf4j
@Component
public class IpUtil {
private static String localIp;
@PostConstruct
public void init() {
try {
localIp = InetAddress.getLocalHost().getHostAddress();
log.info("当前实例 IP: {}", localIp);
} catch (UnknownHostException e) {
log.error("获取本地 IP 失败", e);
localIp = "127.0.0.1";
}
}
public static String getLocalIp() {
return localIp;
}
}
五、生产级实践方案
5.1 Nacos 集群部署架构
客户端集群
数据库层
Nacos 集群节点
负载均衡层
Nginx / SLB
VIP: nacos.example.com:8848
Nacos Node1
192.168.1.10:8848
Nacos Node2
192.168.1.11:8848
Nacos Node3
192.168.1.12:8848
MySQL 主从集群
持久化配置数据
微服务实例1
微服务实例2
微服务实例3
微服务实例N
5.2 集群配置文件
cluster.conf 配置:
properties
# /opt/nacos/conf/cluster.conf
# Nacos 集群节点列表
192.168.1.10:8848
192.168.1.11:8848
192.168.1.12:8848
application.properties 配置:
properties
# /opt/nacos/conf/application.properties
# 服务端口
server.port=8848
# 集群模式
nacos.standalone=false
# 数据库配置(生产环境必须使用 MySQL)
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.1.20:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=nacos
db.password.0=nacos@123
### 指定集群名称
nacos.inetutils.ip-address=192.168.1.10
nacos.inetutils.preferred-networks=192.168.1
# 鉴权配置
nacos.core.auth.enabled=true
nacos.core.auth.server.identity.key=nacos
nacos.core.auth.server.identity.value=nacos
nacos.core.auth.plugin.nacos.token.secret.key=VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMTIzNDU2Nzg5
# JVM 调优参数
# 在 startup.sh 中添加
# JAVA_OPT="${JAVA_OPT} -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
启动脚本:
bash
#!/bin/bash
# nacos-cluster-start.sh
NACOS_HOME=/opt/nacos
NODE_IP=$1
if [ -z "$NODE_IP" ]; then
echo "Usage: $0 <node_ip>"
exit 1
fi
cd $NACOS_HOME
# 修改本节点 IP
sed -i "s/nacos.inetutils.ip-address=.*/nacos.inetutils.ip-address=$NODE_IP/" conf/application.properties
# 启动 Nacos
./bin/startup.sh
echo "Nacos node $NODE_IP started!"
5.3 客户端连接集群配置
yaml
spring:
application:
name: user-service
cloud:
nacos:
config:
# 集群地址列表,用逗号分隔
server-addr: 192.168.1.10:8848,192.168.1.11:8848,192.168.1.12:8848
# 或使用域名+负载均衡
# server-addr: nacos.example.com:8848
file-extension: yaml
group: DEFAULT_GROUP
namespace: ${NAMESPACE_ID:public}
# 失败重试配置
max-retry: 3
config-retry-time: 2000
config-long-poll-timeout: 46000
# 命名空间从环境变量读取(便于多环境部署)
namespace: ${NACOS_NAMESPACE:public}
5.4 配置变更审批流程
创建配置
提交审核
驳回修改
审核通过
测试通过
测试失败
需要修改
开始灰度
灰度回滚
灰度完成
草稿
待审核
待测试
待发布
灰度中
已发布
需要技术负责人
审核通过
测试环境验证
功能完整性检查
指定灰度IP
监控指标正常
5.5 监控与告警
java
package com.example.nacos.monitor;
import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.NacosConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Nacos 配置变更监控与告警
*/
@Slf4j
@Component
public class NacosMonitor {
@Value("${spring.cloud.nacos.config.server-addr}")
private String serverAddr;
/**
* 监控核心配置变更并发送告警
*/
@NacosConfigListener(dataId = "core-config.yaml", groupId = "CORE_GROUP")
public void onCoreConfigChange(String newConfig) {
log.warn("【告警】核心配置已变更!");
// 1. 记录变更日志到数据库
logChangeToDatabase("core-config.yaml", newConfig);
// 2. 发送钉钉/企业微信通知
sendDingTalkAlert("核心配置变更", newConfig);
// 3. 触发配置一致性检查
verifyConfigConsistency();
}
/**
* 监控数据库连接配置变更
*/
@NacosConfigListener(dataId = "datasource-config.yaml", groupId = "DB_GROUP")
public void onDatasourceConfigChange(String newConfig) {
log.warn("【告警】数据源配置已变更!");
// 验证新配置的连接可用性
boolean isValid = validateDatasourceConnection(newConfig);
if (!isValid) {
log.error("❌ 数据源配置验证失败,请检查!");
sendEmergencyAlert("数据源配置异常", "连接验证失败");
}
}
private void logChangeToDatabase(String dataId, String config) {
// 实现记录到数据库的逻辑
}
private void sendDingTalkAlert(String title, String content) {
// 实现钉钉通知逻辑
}
private void sendEmergencyAlert(String title, String content) {
// 实现紧急告警逻辑
}
private boolean validateDatasourceConnection(String config) {
// 实现数据源连接验证逻辑
return true;
}
private void verifyConfigConsistency() {
// 验证各实例配置一致性
}
}
六、完整示例项目
6.1 项目结构
nacos-config-demo/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/nacos/
│ │ │ ├── NacosConfigDemoApplication.java
│ │ │ ├── config/
│ │ │ │ ├── NacosProperties.java
│ │ │ │ └── JasyptConfig.java
│ │ │ ├── controller/
│ │ │ │ └── ConfigController.java
│ │ │ ├── listener/
│ │ │ │ ├── AnnotationConfigListener.java
│ │ │ │ └── ProgrammaticConfigListener.java
│ │ │ ├── service/
│ │ │ │ └── ConfigService.java
│ │ │ └── util/
│ │ │ ├── IpUtil.java
│ │ │ └── JasyptUtil.java
│ │ └── resources/
│ │ ├── application.yml
│ │ ├── application-dev.yml
│ │ ├── application-prod.yml
│ │ └── bootstrap.yml
6.2 pom.xml 完整配置
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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>nacos-config-demo</artifactId>
<version>1.0.0</version>
<name>nacos-config-demo</name>
<description>Nacos 配置中心完整示例</description>
<properties>
<java.version>17</java.version>
<spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version>
<spring-cloud.version>2023.0.0</spring-cloud.version>
<jasypt.version>3.0.5</jasypt.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- Nacos Discovery (可选,服务注册发现) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Spring Cloud Context (支持 @RefreshScope) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<!-- Jasypt 配置加密 -->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>${jasypt.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Hutool 工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.23</version>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<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>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
6.3 配置类与属性绑定
java
package com.example.nacos.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
* Nacos 配置属性绑定
*/
@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "app")
public class AppProperties {
/**
* 应用名称
*/
private String name;
/**
* 应用版本
*/
private String version;
/**
* 运行环境
*/
private String env;
/**
* 业务配置
*/
private Business business;
/**
* 功能开关
*/
private FeatureToggle featureToggle;
@Data
public static class Business {
private Integer maxRetry;
private Long timeout;
}
@Data
public static class FeatureToggle {
private Boolean enableCache;
private Boolean enableNewAlgo;
}
}
6.4 配置控制器
java
package com.example.nacos.controller;
import com.example.nacos.config.AppProperties;
import com.example.nacos.service.ConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 配置查询控制器
*/
@Slf4j
@RestController
@RequestMapping("/config")
@RequiredArgsConstructor
@RefreshScope
public class ConfigController {
private final AppProperties appProperties;
private final ConfigService configService;
@Value("${server.port}")
private String serverPort;
@GetMapping("/all")
public Map<String, Object> getAllConfig() {
Map<String, Object> result = new HashMap<>();
result.put("appName", appProperties.getName());
result.put("appVersion", appProperties.getVersion());
result.put("appEnv", appProperties.getEnv());
result.put("serverPort", serverPort);
result.put("business", appProperties.getBusiness());
result.put("featureToggle", appProperties.getFeatureToggle());
result.put("instanceIp", configService.getInstanceIp());
result.put("configSource", "Nacos");
return result;
}
@GetMapping("/name")
public String getAppName() {
return appProperties.getName();
}
@GetMapping("/version")
public String getAppVersion() {
return appProperties.getVersion();
}
@GetMapping("/feature-cache")
public Boolean isCacheEnabled() {
return appProperties.getFeatureToggle().getEnableCache();
}
@GetMapping("/refresh-info")
public Map<String, Object> getRefreshInfo() {
Map<String, Object> info = new HashMap<>();
info.put("refreshScopeActive", true);
info.put("configSource", configService.getConfigSource());
info.put("lastRefreshTime", configService.getLastRefreshTime());
return info;
}
}
6.5 Bootstrap 配置
yaml
# bootstrap.yml
spring:
application:
name: nacos-config-demo
profiles:
active: ${ENV:dev}
cloud:
nacos:
config:
# Nacos 服务地址
server-addr: ${NACOS_ADDR:127.0.0.1:8848}
# 配置文件格式
file-extension: yaml
# 配置分组
group: DEFAULT_GROUP
# 命名空间 ID(从环境变量读取)
namespace: ${NACOS_NAMESPACE:public}
# 共享配置
shared-configs:
- data-id: common-redis.yaml
group: COMMON_GROUP
refresh: true
- data-id: common-mq.yaml
group: COMMON_GROUP
refresh: true
# 扩展配置
extension-configs:
- data-id: demo-business.yaml
group: DEMO_GROUP
refresh: true
# 失败重试配置
max-retry: 3
config-retry-time: 2000
config-long-poll-timeout: 46000
# 编码格式
encode: utf-8
# 启用配置刷新
refresh-enabled: true
# 启用 bootstrap 上下文(Spring Boot 2.4+ 需要)
main:
allow-bean-definition-overriding: true
---
# 启用 Bootstrap
# application.properties
# spring.cloud.bootstrap.enabled=true
6.6 Actuator 监控配置
yaml
# application.yml
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
refresh:
enabled: true
env:
show-values: always
configprops:
show-values: always
logging:
level:
com.alibaba.nacos: DEBUG
com.example.nacos: DEBUG
七、常见问题与解决方案
7.1 问题诊断流程图
不通
正常
未配置
已配置
不匹配
匹配
错误
正确
未启动
已启动
无权限
有权限
配置无法加载
检查网络连通性
检查 Nacos 地址
检查防火墙规则
检查 bootstrap.yml
添加 bootstrap 配置
检查 Data ID/Group
核对命名规则
检查大小写
检查 Namespace
确认使用 ID 而非名称
检查 Nacos Server
启动 Nacos 服务
检查权限配置
配置 ACL 权限
查看详细日志
7.2 问题排查清单
| 问题现象 | 可能原因 | 排查命令/方法 | 解决方案 |
|---|---|---|---|
| 无法连接 Nacos | 地址错误/网络不通 | curl http://nacos-addr:8848/nacos/ |
检查 server-addr 配置 |
| 配置未加载 | bootstrap 未启用 | 检查日志中是否有 PropertySource |
添加 spring.cloud.bootstrap.enabled=true |
| 配置不刷新 | 缺少 @RefreshScope | 检查 Bean 是否有注解 | 添加 @RefreshScope |
| Data ID 不存在 | 命名规则错误 | 对比控制台配置 | 检查 ${name}-${profile}.${ext} 格式 |
| 连接被拒绝 | 端口占用/防火墙 | `netstat -an | grep 8848` |
| 权限不足 | ACL 鉴权开启 | 检查 application.properties | 配置用户权限或关闭鉴权 |
| 配置乱码 | 编码不一致 | 检查文件编码格式 | 统一使用 UTF-8 |
7.3 常用排查命令
bash
# 1. 检查 Nacos 服务状态
curl http://127.0.0.1:8848/nacos/v1/console/health/readiness
# 2. 获取配置(直接 API 调用)
curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example.yaml&group=DEFAULT_GROUP"
# 3. 检查命名空间
curl -X GET "http://127.0.0.1:8848/nacos/v1/console/namespaces"
# 4. 查看应用日志
tail -f logs/spring.log | grep -i nacos
# 5. 检查端口监听
netstat -tlnp | grep 8848
# 或
ss -tlnp | grep 8848
# 6. Docker 容器日志
docker logs -f nacos-standalone
# 7. 测试长轮询
curl "http://127.0.0.1:8848/nacos/v1/cs/configs/listener"
八、 总结与学习路径
第一阶段内容
学习路径
第四阶段内容
集群部署
高可用架构
监控告警
性能调优
第三阶段内容
配置监听器
配置加密
共享配置
灰度发布
第二阶段内容
多环境配置
命名空间隔离
配置分组
动态刷新
第一阶段
基础入门
1-2天
第二阶段
核心特性
3-5天
第三阶段
进阶实践
1-2周
第四阶段
生产精通
2-4周
安装部署
创建配置
Spring Boot 接入
基础读取配置
核心能力掌握清单
✅ 基础能力
├─ Nacos 单机/集群部署
├─ 创建和管理配置
├─ Spring Boot 集成
└─ 配置读取与注入
✅ 核心特性
├─ 多环境配置隔离(Profile/Namespace)
├─ 配置分组(Group)
├─ 共享配置(shared-configs)
├─ 动态刷新(@RefreshScope)
└─ 配置优先级理解
✅ 高级特性
├─ 配置变更监听(编程/注解)
├─ 敏感信息加密(Jasypt)
├─ 灰度发布(Beta)
├─ 配置版本回滚
└─ 权限控制(ACL)
✅ 生产实践
├─ 高可用集群部署
├─ 监控与告警
├─ 配置变更审批流程
├─ 灾难恢复方案
└─ 性能调优
参考资源
| 资源类型 | 链接 |
|---|---|
| 官方文档 | https://nacos.io/zh-cn/docs/what-is-nacos.html |
| GitHub 仓库 | https://github.com/alibaba/nacos |
| Spring Cloud Alibaba | https://sca.aliyun.com/docs/2023/overview/version-explain/ |
| 集群部署指南 | https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html |
| API 文档 | https://nacos.io/zh-cn/docs/open-api.html |