一、配置管理的烦恼
零基础全栈开发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)
// 服务启动时1.从Nacos拉取配置2.加载到Spring环境3.创建Bean// 定时任务每30秒拉取一次,检查配置变没变2. 推模式(Push)
1.配置改了,Nacos通知服务2.服务收到通知,拉取新配置3.刷新Bean(@RefreshScope)3. 配置结构
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:用户服务公共配置
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:用户服务开发环境
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:用户服务生产环境
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:
<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(重点!必须用这个文件名):
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.ymlextension-configs:-data-id:user-service.yamlgroup:DEFAULT_GROUPrefresh:true# 是否刷新-data-id:user-service-${spring.profiles.active}.yamlgroup:DEFAULT_GROUPrefresh:trueapplication.yml(本地保留少量配置):
# 这里只放本地特有的配置,或者默认值spring:profiles:active:dev# 激活的环境# 本地可以覆盖Nacos的配置# 但建议能放Nacos就放Nacos3. 测试配置生效
@RestController@RequestMapping("/config")publicclassConfigController{@Value("${server.port}")privateStringport;@Value("${spring.datasource.url}")privateStringdbUrl;@Value("${logging.level.com.example}")privateStringlogLevel;@GetMapping("/show")publicMap<String,String>showConfig(){Map<String,String>config=newHashMap<>();config.put("port",port);config.put("dbUrl",dbUrl);config.put("logLevel",logLevel);returnconfig;}}访问http://localhost:8081/config/show,应该显示Nacos里的配置。
六、配置动态刷新(热更新)
场景:双11改折扣
商品服务有个折扣配置:
# 在Nacos配置sale:discount:0.8# 8折步骤1:创建配置Bean
@Component@ConfigurationProperties(prefix="sale")@RefreshScope// 重点!支持动态刷新@DatapublicclassSaleConfig{privateDoublediscount=1.0;// 默认不打折privateIntegerfullReduction=0;// 满减privateBooleanflashSale=false;// 是否限时抢购}步骤2:使用配置
@RestController@RequestMapping("/product")publicclassProductController{@AutowiredprivateSaleConfigsaleConfig;@GetMapping("/price/{originalPrice}")publicDoublecalculatePrice(@PathVariableDoubleoriginalPrice){// 动态读取配置returnoriginalPrice*saleConfig.getDiscount();}@GetMapping("/config")publicSaleConfiggetConfig(){returnsaleConfig;}}步骤3:测试热更新
- 启动服务,访问
http://localhost:8083/product/config - 看到折扣是0.8(8折)
- 不要重启服务,去Nacos控制台
- 修改
product-service.yaml:sale: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(本地,最低优先级)
示例配置:
spring:cloud:nacos:config:# 1. 先加载 common.yaml(基础配置)extension-configs[0]:data-id:common.yamlgroup:DEFAULT_GROUPrefresh:true# 2. 再加载 middleware.yaml(中间件配置)extension-configs[1]:data-id:middleware.yamlgroup:DEFAULT_GROUPrefresh:true# 3. 加载应用配置#># 4. 最后加载环境配置#>共享配置(所有服务都用)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
# 在bootstrap.yml里shared-configs:-data-id:common.yamlgroup:DEFAULT_GROUPrefresh:true
八、多环境配置
方案1:用Namespace(命名空间)
在Nacos创建命名空间:
- dev(开发)
- test(测试)
- prod(生产)
每个环境一套配置
服务启动时指定namespace
spring:cloud:nacos:config:namespace:dev# 开发环境# 或者用环境变量namespace:${NACOS_NAMESPACE:dev}
方案2:用Group(分组)
spring:profiles:active:devcloud:nacos:config:group:${spring.profiles.active}# 根据环境选分组
方案3:用Data ID后缀
Data ID格式:${spring.application.name}-${环境}.yaml 例如: - user-service-dev.yaml - user-service-test.yaml - user-service-prod.yaml
spring:cloud:nacos:config:# 自动拼接环境name:${spring.application.name}file-extension:yaml# Nacos会找:user-service-dev.yaml
九、敏感配置加密
场景:数据库密码不能明文存
步骤1:加Jasypt依赖
<dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.5</version></dependency>
步骤2:生成加密值
@SpringBootApplicationpublicclassTestApp{publicstaticvoidmain(String[]args){StandardPBEStringEncryptorencryptor=newStandardPBEStringEncryptor();encryptor.setPassword("mySecretKey");// 加密密钥Stringencrypted=encryptor.encrypt("123456");System.out.println("加密后: "+encrypted);// 输出:g8N5jJYVWp9jF6Bz8n4K7Q==}}
步骤3:Nacos配置用加密值
spring:datasource:password:ENC(g8N5jJYVWp9jF6Bz8n4K7Q==)# 用ENC()包裹
步骤4:启动时传入密钥
# 方式1:启动参数java -jar app.jar --jasypt.encryptor.password=mySecretKey# 方式2:环境变量exportJASYPT_ENCRYPTOR_PASSWORD=mySecretKey java -jar app.jar# 方式3:配置文件(不安全)# jasypt.encryptor.password=mySecretKey
十、配置的最佳实践
1. 配置分类存放
Nacos配置: ├── common.yaml(所有服务共享) ├── middleware.yaml(中间件配置) ├── user-service.yaml(用户服务配置) ├── user-service-dev.yaml(开发环境) └── user-service-prod.yaml(生产环境)
2. 配置版本管理
- 每次修改前备份
- 使用配置历史功能
- 重要配置变更要评审
3. 配置监控
@ComponentpublicclassConfigChangeListener{// 监听配置变更@EventListenerpublicvoidhandleRefresh(RefreshScopeRefreshedEventevent){System.out.println("配置已刷新: "+newDate());// 发送通知// 记录日志// 刷新缓存}}
4. 配置回滚
- Nacos控制台 -> 配置详情 -> 历史版本
- 选择要回滚的版本
- 点回滚
- 所有服务自动生效
5. 配置检查
@RestController@RequestMapping("/actuator")publicclassConfigCheckController{@AutowiredprivateEnvironmentenvironment;@GetMapping("/config-check")publicMap<String,Object>checkConfig(){Map<String,Object>result=newHashMap<>();// 检查必要配置String[]requiredProps={"spring.datasource.url","spring.datasource.username","spring.redis.host"};for(Stringprop:requiredProps){Stringvalue=environment.getProperty(prop);result.put(prop,value!=null?"OK":"MISSING");}returnresult;}}
十一、常见问题解决
1. 配置不生效
原因:加载顺序问题
解决:
# bootstrap.ymlspring:cloud:nacos:config:# 明确指定加载哪些配置extension-configs[0]:data-id:common.yamlgroup:DEFAULT_GROUPrefresh:trueextension-configs[1]:data-id:${spring.application.name}.yamlgroup:DEFAULT_GROUPrefresh:true
2. 动态刷新不生效
原因:
- 没加
@RefreshScope - 配置没在Nacos里
- 没加
spring-cloud-starter-bootstrap
解决:
// 1. 类上加@RefreshScope// 2. 确保配置在Nacos// 3. 检查依赖
3. 配置冲突
现象:本地配置覆盖了Nacos配置
解决:
# application.yml里尽量少放配置# 只放本地测试需要的spring:cloud:nacos:config:override-none:true# 本地不覆盖远程override-system-properties:false# 系统属性不覆盖
4. 启动报错:找不到配置
原因:Nacos连接失败或配置不存在
解决:
spring:cloud:nacos:config:# 允许配置不存在refresh-enabled:true# 设置超时timeout:3000# 失败重试max-retry:3retry-interval:1000
十二、实际项目配置示例
完整bootstrap.yml
spring:application:name:user-serviceprofiles: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:yamlrefresh-enabled:true# 共享配置(所有服务)shared-configs:-data-id:common.yamlgroup:COMMON_GROUPrefresh:true-data-id:datasource.yamlgroup:MIDDLEWARE_GROUPrefresh:true-data-id:redis.yamlgroup:MIDDLEWARE_GROUPrefresh:true# 扩展配置(本服务)extension-configs:-data-id:${spring.application.name}.yamlgroup:DEFAULT_GROUPrefresh:true-data-id:${spring.application.name}-${spring.profiles.active}.yamlgroup:DEFAULT_GROUPrefresh:true# 本地默认值(开发环境方便)server:port:8081logging:level:root:infocom.example:debug
Nacos配置文件示例
common.yaml(所有服务共享):
# 应用通用配置app:version:1.0.0env:${spring.profiles.active}# 日期时间格式spring:jackson:date-format:yyyy-MM-dd HH:mm:sstime-zone:GMT+8default-property-inclusion:non_null# 文件上传servlet:multipart:max-file-size:10MBmax-request-size:10MB# 日志logging:pattern:console:"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
datasource.yaml(数据库配置):
spring:datasource:type:com.zaxxer.hikari.HikariDataSourcedriver-class-name:com.mysql.cj.jdbc.Driverhikari:minimum-idle:5maximum-pool-size:20idle-timeout:30000max-lifetime:1800000connection-timeout:30000connection-test-query:SELECT 1# Mybatismybatis:configuration:map-underscore-to-camel-case:truelog-impl:org.apache.ibatis.logging.stdout.StdOutImpl
十三、今儿个总结
零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。
学会了啥?
- ✅ 配置中心的作用(一处改,处处生效)
- ✅ Nacos配置中心的使用
- ✅ 配置文件加载顺序
- ✅ 动态刷新(@RefreshScope)
- ✅ 多环境配置
- ✅ 配置加密
- ✅ 最佳实践
关键点
- bootstrap.yml优先加载
- @RefreshScope支持热更新
- 命名空间隔离环境
- 配置优先级要清楚
- 敏感信息要加密
十四、明儿个学啥?
零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。
明天咱学分布式事务!
- 用户下单,扣库存,这两步要一起成功或一起失败
- 跨服务的事务怎么保证一致性
- Seata是啥,咋用
- 分布式事务的几种方案
明天咱解决钱不能算错的问题!💰