一、配置管理的烦恼
零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。
场景1:数据库密码改了
以前:每个微服务都连数据库,密码改了得:
- 改user-service的
application.yml - 改order-service的
application.yml - 改product-service的
application.yml - 每个服务都得重启
- 生产环境还得走发布流程
太麻烦了!
场景2:双11活动配置
活动期间:
- 商品打8折
- 满200减30
- 限时抢购
以前:改配置 -> 打包 -> 发布 -> 重启 活动都结束了,服务还没重启完!
场景3:不同环境不同配置
- 开发环境:用本地数据库
- 测试环境:用测试数据库
- 生产环境:用生产数据库
以前:打包时切换profile,容易出错!
二、配置中心是啥?
就像公司的公告板:
- 所有配置都写在公告板上
- 员工(微服务)每天上班先看公告板
- 公告板改了,员工自动知道
- 不用每个人挨个通知
配置中心的好处:
- 一处改,处处生效
- 热更新:不用重启服务
- 版本管理:可以回滚
- 权限控制:谁能改配置
- 环境隔离:开发、测试、生产分开
三、为啥选Nacos配置中心?
| 配置中心 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Spring Cloud Config | Spring亲儿子,集成好 | 需要配合Git,功能简单 | 简单项目 |
| Apollo | 功能强大,界面好 | 部署复杂,太重 | 大厂,复杂项目 |
| Nacos | 配置+注册一体,轻量 | 功能不如Apollo全 | 中小项目,Spring Cloud Alibaba |
| Consul | 配置+注册+健康检查 | 对Spring Cloud支持一般 | Go项目多 |
咱们选Nacos,因为:
- 已经用Nacos做注册中心了
- 配置管理功能够用
- 跟Spring Cloud Alibaba集成好
- 部署简单
四、Nacos配置中心原理
1. 拉模式(Pull)
java
// 服务启动时
1. 从Nacos拉取配置
2. 加载到Spring环境
3. 创建Bean
// 定时任务
每30秒拉取一次,检查配置变没变
2. 推模式(Push)
java
1. 配置改了,Nacos通知服务
2. 服务收到通知,拉取新配置
3. 刷新Bean(@RefreshScope)
3. 配置结构
sql
Data ID: user-service-dev.yaml
Group: DEFAULT_GROUP
Namespace: dev
相当于:
文件位置:dev/DEFAULT_GROUP/user-service-dev.yaml
五、开整!把配置挪到Nacos
零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。
步骤1:Nacos控制台加配置
- 访问
http://localhost:8848/nacos - 左边菜单:配置管理 -> 配置列表
- 点右上角:+
配置1:用户服务公共配置
yaml
Data ID: user-service.yaml
Group: DEFAULT_GROUP
配置格式: YAML
配置内容:
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://localhost:3306/user_db?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
配置2:用户服务开发环境
yaml
Data ID: user-service-dev.yaml
Group: DEFAULT_GROUP
配置内容:
spring:
datasource:
url: jdbc:mysql://localhost:3306/user_db_dev?useSSL=false
logging:
level:
com.example: debug
配置3:用户服务生产环境
yaml
Data ID: user-service-prod.yaml
Group: DEFAULT_GROUP
配置内容:
spring:
datasource:
url: jdbc:mysql://prod-mysql:3306/user_db?useSSL=false
password: ${DB_PASSWORD:强密码}
logging:
level:
com.example: info
步骤2:改造user-service
1. 加依赖
pom.xml:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 配置刷新 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
2. 加配置文件
bootstrap.yml(重点!必须用这个文件名):
yaml
spring:
application:
name: user-service # 服务名,一定要有!
cloud:
nacos:
config:
server-addr: localhost:8848 # Nacos地址
file-extension: yaml # 配置文件格式
group: DEFAULT_GROUP # 分组,默认就是这个
namespace: dev # 命名空间,对应环境
# 配置内容(重要!)
# 1. 先加载user-service.yaml(公共配置)
# 2. 再加载user-service-dev.yaml(环境配置)
# 3. 最后加载本地application.yml
extension-configs:
- data-id: user-service.yaml
group: DEFAULT_GROUP
refresh: true # 是否刷新
- data-id: user-service-${spring.profiles.active}.yaml
group: DEFAULT_GROUP
refresh: true
application.yml(本地保留少量配置):
yaml
# 这里只放本地特有的配置,或者默认值
spring:
profiles:
active: dev # 激活的环境
# 本地可以覆盖Nacos的配置
# 但建议能放Nacos就放Nacos
3. 测试配置生效
java
@RestController
@RequestMapping("/config")
public class ConfigController {
@Value("${server.port}")
private String port;
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${logging.level.com.example}")
private String logLevel;
@GetMapping("/show")
public Map<String, String> showConfig() {
Map<String, String> config = new HashMap<>();
config.put("port", port);
config.put("dbUrl", dbUrl);
config.put("logLevel", logLevel);
return config;
}
}
访问http://localhost:8081/config/show,应该显示Nacos里的配置。
六、配置动态刷新(热更新)
场景:双11改折扣
商品服务有个折扣配置:
yaml
# 在Nacos配置
sale:
discount: 0.8 # 8折
步骤1:创建配置Bean
java
@Component
@ConfigurationProperties(prefix = "sale")
@RefreshScope // 重点!支持动态刷新
@Data
public class SaleConfig {
private Double discount = 1.0; // 默认不打折
private Integer fullReduction = 0; // 满减
private Boolean flashSale = false; // 是否限时抢购
}
步骤2:使用配置
java
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private SaleConfig saleConfig;
@GetMapping("/price/{originalPrice}")
public Double calculatePrice(@PathVariable Double originalPrice) {
// 动态读取配置
return originalPrice * saleConfig.getDiscount();
}
@GetMapping("/config")
public SaleConfig getConfig() {
return saleConfig;
}
}
步骤3:测试热更新
-
启动服务,访问
http://localhost:8083/product/config -
看到折扣是0.8(8折)
-
不要重启服务,去Nacos控制台
-
修改
product-service.yaml:yamlsale: discount: 0.7 # 改成7折 fullReduction: 30 # 满200减30 -
点发布
-
刷新页面,配置自动变成7折!
七、配置的优先级(重要!)
加载顺序(后加载的覆盖先加载的):
- bootstrap.yml(本地,最高优先级)
- Nacos扩展配置(extension-configs,按数组顺序)
- Nacos共享配置(shared-configs)
- Nacos主配置(data-id: ${spring.application.name}.yaml)
- application.yml(本地,最低优先级)
示例配置:
yaml
spring:
cloud:
nacos:
config:
# 1. 先加载 common.yaml(基础配置)
extension-configs[0]:
data-id: common.yaml
group: DEFAULT_GROUP
refresh: true
# 2. 再加载 middleware.yaml(中间件配置)
extension-configs[1]:
data-id: middleware.yaml
group: DEFAULT_GROUP
refresh: true
# 3. 加载应用配置
# data-id: user-service.yaml(根据spring.application.name)
# 4. 最后加载环境配置
# data-id: user-service-dev.yaml
共享配置(所有服务都用)
yaml
Data ID: common.yaml
内容:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mybatis:
configuration:
map-underscore-to-camel-case: true
yaml
# 在bootstrap.yml里
shared-configs:
- data-id: common.yaml
group: DEFAULT_GROUP
refresh: true
八、多环境配置
方案1:用Namespace(命名空间)
-
在Nacos创建命名空间:
- dev(开发)
- test(测试)
- prod(生产)
-
每个环境一套配置
-
服务启动时指定namespace
yaml
spring:
cloud:
nacos:
config:
namespace: dev # 开发环境
# 或者用环境变量
namespace: ${NACOS_NAMESPACE:dev}
方案2:用Group(分组)
yaml
spring:
profiles:
active: dev
cloud:
nacos:
config:
group: ${spring.profiles.active} # 根据环境选分组
方案3:用Data ID后缀
diff
Data ID格式:${spring.application.name}-${环境}.yaml
例如:
- user-service-dev.yaml
- user-service-test.yaml
- user-service-prod.yaml
yaml
spring:
cloud:
nacos:
config:
# 自动拼接环境
name: ${spring.application.name}
file-extension: yaml
# Nacos会找:user-service-dev.yaml
九、敏感配置加密
场景:数据库密码不能明文存
步骤1:加Jasypt依赖
xml
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
步骤2:生成加密值
java
@SpringBootApplication
public class TestApp {
public static void main(String[] args) {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("mySecretKey"); // 加密密钥
String encrypted = encryptor.encrypt("123456");
System.out.println("加密后: " + encrypted);
// 输出:g8N5jJYVWp9jF6Bz8n4K7Q==
}
}
步骤3:Nacos配置用加密值
yaml
spring:
datasource:
password: ENC(g8N5jJYVWp9jF6Bz8n4K7Q==) # 用ENC()包裹
步骤4:启动时传入密钥
bash
# 方式1:启动参数
java -jar app.jar --jasypt.encryptor.password=mySecretKey
# 方式2:环境变量
export JASYPT_ENCRYPTOR_PASSWORD=mySecretKey
java -jar app.jar
# 方式3:配置文件(不安全)
# jasypt.encryptor.password=mySecretKey
十、配置的最佳实践
1. 配置分类存放
sql
Nacos配置:
├── common.yaml(所有服务共享)
├── middleware.yaml(中间件配置)
├── user-service.yaml(用户服务配置)
├── user-service-dev.yaml(开发环境)
└── user-service-prod.yaml(生产环境)
2. 配置版本管理
- 每次修改前备份
- 使用配置历史功能
- 重要配置变更要评审
3. 配置监控
java
@Component
public class ConfigChangeListener {
// 监听配置变更
@EventListener
public void handleRefresh(RefreshScopeRefreshedEvent event) {
System.out.println("配置已刷新: " + new Date());
// 发送通知
// 记录日志
// 刷新缓存
}
}
4. 配置回滚
- Nacos控制台 -> 配置详情 -> 历史版本
- 选择要回滚的版本
- 点回滚
- 所有服务自动生效
5. 配置检查
java
@RestController
@RequestMapping("/actuator")
public class ConfigCheckController {
@Autowired
private Environment environment;
@GetMapping("/config-check")
public Map<String, Object> checkConfig() {
Map<String, Object> result = new HashMap<>();
// 检查必要配置
String[] requiredProps = {
"spring.datasource.url",
"spring.datasource.username",
"spring.redis.host"
};
for (String prop : requiredProps) {
String value = environment.getProperty(prop);
result.put(prop, value != null ? "OK" : "MISSING");
}
return result;
}
}
十一、常见问题解决
1. 配置不生效
原因 :加载顺序问题 解决:
yaml
# bootstrap.yml
spring:
cloud:
nacos:
config:
# 明确指定加载哪些配置
extension-configs[0]:
data-id: common.yaml
group: DEFAULT_GROUP
refresh: true
extension-configs[1]:
data-id: ${spring.application.name}.yaml
group: DEFAULT_GROUP
refresh: true
2. 动态刷新不生效
原因:
- 没加
@RefreshScope - 配置没在Nacos里
- 没加
spring-cloud-starter-bootstrap
解决:
java
// 1. 类上加@RefreshScope
// 2. 确保配置在Nacos
// 3. 检查依赖
3. 配置冲突
现象 :本地配置覆盖了Nacos配置 解决:
yaml
# application.yml里尽量少放配置
# 只放本地测试需要的
spring:
cloud:
nacos:
config:
override-none: true # 本地不覆盖远程
override-system-properties: false # 系统属性不覆盖
4. 启动报错:找不到配置
原因 :Nacos连接失败或配置不存在 解决:
yaml
spring:
cloud:
nacos:
config:
# 允许配置不存在
refresh-enabled: true
# 设置超时
timeout: 3000
# 失败重试
max-retry: 3
retry-interval: 1000
十二、实际项目配置示例
完整bootstrap.yml
yaml
spring:
application:
name: user-service
profiles:
active: ${PROFILE:dev} # 从环境变量读取
cloud:
nacos:
config:
server-addr: ${NACOS_HOST:localhost}:${NACOS_PORT:8848}
username: ${NACOS_USERNAME:nacos}
password: ${NACOS_PASSWORD:nacos}
namespace: ${NACOS_NAMESPACE:dev}
file-extension: yaml
refresh-enabled: true
# 共享配置(所有服务)
shared-configs:
- data-id: common.yaml
group: COMMON_GROUP
refresh: true
- data-id: datasource.yaml
group: MIDDLEWARE_GROUP
refresh: true
- data-id: redis.yaml
group: MIDDLEWARE_GROUP
refresh: true
# 扩展配置(本服务)
extension-configs:
- data-id: ${spring.application.name}.yaml
group: DEFAULT_GROUP
refresh: true
- data-id: ${spring.application.name}-${spring.profiles.active}.yaml
group: DEFAULT_GROUP
refresh: true
# 本地默认值(开发环境方便)
server:
port: 8081
logging:
level:
root: info
com.example: debug
Nacos配置文件示例
common.yaml(所有服务共享):
yaml
# 应用通用配置
app:
version: 1.0.0
env: ${spring.profiles.active}
# 日期时间格式
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: non_null
# 文件上传
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
# 日志
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
datasource.yaml(数据库配置):
yaml
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
# Mybatis
mybatis:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
十三、今儿个总结
零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。
学会了啥?
- ✅ 配置中心的作用(一处改,处处生效)
- ✅ Nacos配置中心的使用
- ✅ 配置文件加载顺序
- ✅ 动态刷新(@RefreshScope)
- ✅ 多环境配置
- ✅ 配置加密
- ✅ 最佳实践
关键点
- bootstrap.yml优先加载
- @RefreshScope支持热更新
- 命名空间隔离环境
- 配置优先级要清楚
- 敏感信息要加密
十四、明儿个学啥?
零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。
明天咱学分布式事务!
- 用户下单,扣库存,这两步要一起成功或一起失败
- 跨服务的事务怎么保证一致性
- Seata是啥,咋用
- 分布式事务的几种方案
明天咱解决钱不能算错的问题!💰