当前位置:首页>java>配置中心 - 不用改代码就能改配置

配置中心 - 不用改代码就能改配置

  • 2026-10-28 09:31:37
配置中心 - 不用改代码就能改配置

一、配置管理的烦恼

场景1:数据库密码改了

以前:每个微服务都连数据库,密码改了得:

  1. 改user-service的application.yml

  2. 改order-service的application.yml

  3. 改product-service的application.yml

  4. 每个服务都得重启

  5. 生产环境还得走发布流程

太麻烦了!

场景2:双11活动配置

活动期间:

  • 商品打8折

  • 满200减30

  • 限时抢购

以前:改配置 -> 打包 -> 发布 -> 重启

活动都结束了,服务还没重启完!

场景3:不同环境不同配置

  • 开发环境:用本地数据库

  • 测试环境:用测试数据库

  • 生产环境:用生产数据库

以前:打包时切换profile,容易出错!

二、配置中心是啥?

就像公司的公告板:

  • 所有配置都写在公告板上

  • 员工(微服务)每天上班先看公告板

  • 公告板改了,员工自动知道

  • 不用每个人挨个通知

配置中心的好处:

  1. 一处改,处处生效

  2. 热更新:不用重启服务

  3. 版本管理:可以回滚

  4. 权限控制:谁能改配置

  5. 环境隔离:开发、测试、生产分开

三、为啥选Nacos配置中心?

配置中心

优点

缺点

适用场景

Spring Cloud Config

Spring亲儿子,集成好

需要配合Git,功能简单

简单项目

Apollo

功能强大,界面好

部署复杂,太重

大厂,复杂项目

Nacos

配置+注册一体,轻量

功能不如Apollo全

中小项目,Spring Cloud Alibaba

Consul

配置+注册+健康检查

对Spring Cloud支持一般

Go项目多

咱们选Nacos,因为:

  1. 已经用Nacos做注册中心了

  2. 配置管理功能够用

  3. 跟Spring Cloud Alibaba集成好

  4. 部署简单

四、Nacos配置中心原理

1. 拉模式(Pull)

// 服务启动时1. 从Nacos拉取配置2. 加载到Spring环境3. 创建Bean// 定时任务每30秒拉取一次,检查配置变没变

2. 推模式(Push)

1. 配置改了,Nacos通知服务2. 服务收到通知,拉取新配置3. 刷新Bean(@RefreshScope)

3. 配置结构

Data ID: user-service-dev.yamlGroup: DEFAULT_GROUPNamespace: dev相当于:文件位置:dev/DEFAULT_GROUP/user-service-dev.yaml

五、开整!把配置挪到Nacos

步骤1:Nacos控制台加配置

  1. 访问http://localhost:8848/nacos

  2. 左边菜单:配置管理 -> 配置列表

  3. 点右上角:+

配置1:用户服务公共配置

Data ID: user-service.yamlGroup: DEFAULT_GROUP配置格式: YAML配置内容:server:  port: 8081spring:  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.yamlGroup: DEFAULT_GROUP配置内容:spring:  datasource:    url: jdbc:mysql://localhost:3306/user_db_dev?useSSL=falselogging:  level:    com.example: debug

配置3:用户服务生产环境

Data ID: user-service-prod.yamlGroup: 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.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(本地保留少量配置):

# 这里只放本地特有的配置,或者默认值spring:  profiles:    active: dev  # 激活的环境  # 本地可以覆盖Nacos的配置  # 但建议能放Nacos就放Nacos

3. 测试配置生效

@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改折扣

商品服务有个折扣配置:

# 在Nacos配置sale:  discount: 0.8  # 8折

步骤1:创建配置Bean

@Component@ConfigurationProperties(prefix = "sale")@RefreshScope  // 重点!支持动态刷新@Datapublic class SaleConfig {    private Double discount = 1.0;  // 默认不打折    private Integer fullReduction = 0;  // 满减    private Boolean flashSale = false;  // 是否限时抢购}

步骤2:使用配置

@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:测试热更新

  1. 启动服务,访问http://localhost:8083/product/config

  2. 看到折扣是0.8(8折)

  3. 不要重启服务,去Nacos控制台

  4. 修改product-service.yaml:

    sale:  discount: 0.7  # 改成7折  fullReduction: 30  # 满200减30
  5. 点发布

  6. 刷新页面,配置自动变成7折!

七、配置的优先级(重要!)

加载顺序(后加载的覆盖先加载的):

  1. bootstrap.yml(本地,最高优先级)

  2. Nacos扩展配置(extension-configs,按数组顺序)

  3. Nacos共享配置(shared-configs)

  4. Nacos主配置(data-id: ${spring.application.name}.yaml)

  5. application.yml(本地,最低优先级)

示例配置:

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

共享配置(所有服务都用)

Data ID: common.yaml内容:spring:  jackson:    date-format: yyyy-MM-dd HH:mm:ss    time-zone: GMT+8mybatis:  configuration:    map-underscore-to-camel-case: true
# 在bootstrap.yml里shared-configs:  - data-id: common.yaml    group: DEFAULT_GROUP    refresh: true

八、多环境配置

方案1:用Namespace(命名空间)

  1. 在Nacos创建命名空间:

    • dev(开发)

    • test(测试)

    • prod(生产)

  2. 每个环境一套配置

  3. 服务启动时指定namespace

spring:  cloud:    nacos:      config:        namespace: dev  # 开发环境        # 或者用环境变量        namespace: ${NACOS_NAMESPACE:dev}

方案2:用Group(分组)

spring:  profiles:    active: dev  cloud:    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:生成加密值

@SpringBootApplicationpublic 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配置用加密值

spring:  datasource:    password: ENC(g8N5jJYVWp9jF6Bz8n4K7Q==)  # 用ENC()包裹

步骤4:启动时传入密钥

# 方式1:启动参数java -jar app.jar --jasypt.encryptor.password=mySecretKey# 方式2:环境变量export JASYPT_ENCRYPTOR_PASSWORD=mySecretKeyjava -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. 配置监控

@Componentpublic class ConfigChangeListener {    // 监听配置变更    @EventListener    public void handleRefresh(RefreshScopeRefreshedEvent event) {        System.out.println("配置已刷新: " + new Date());        // 发送通知        // 记录日志        // 刷新缓存    }}

4. 配置回滚

  1. Nacos控制台 -> 配置详情 -> 历史版本

  2. 选择要回滚的版本

  3. 点回滚

  4. 所有服务自动生效

5. 配置检查

@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. 配置不生效

原因:加载顺序问题

解决:

# bootstrap.ymlspring:  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. 动态刷新不生效

原因:

  1. 没加@RefreshScope

  2. 配置没在Nacos里

  3. 没加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: 3        retry-interval: 1000

十二、实际项目配置示例

完整bootstrap.yml

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: 8081logging:  level:    root: info    com.example: debug

Nacos配置文件示例

common.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(数据库配置):

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# Mybatismybatis:  configuration:    map-underscore-to-camel-case: true    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

十三、今儿个总结

学会了啥?

  1. ✅ 配置中心的作用(一处改,处处生效)

  2. ✅ Nacos配置中心的使用

  3. ✅ 配置文件加载顺序

  4. ✅ 动态刷新(@RefreshScope)

  5. ✅ 多环境配置

  6. ✅ 配置加密

  7. ✅ 最佳实践

关键点

  1. bootstrap.yml优先加载

  2. @RefreshScope支持热更新

  3. 命名空间隔离环境

  4. 配置优先级要清楚

  5. 敏感信息要加密

十四、明儿个学啥?

明天咱学分布式事务!

  • 用户下单,扣库存,这两步要一起成功或一起失败

  • 跨服务的事务怎么保证一致性

  • Seata是啥,咋用

  • 分布式事务的几种方案

明天咱解决钱不能算错的问题!💰

猜您喜欢
往期精选▼

1. 2026年SpringCloudAlibaba全家桶+三个全栈零基础实战项目

2. 别再瞎学了!这才是Java基础最正确的打开方式,少走90%弯路

3. Spring Boot4.0整合RabbitMQ死信队列实战

4. Spring Boot + Redis 分布式锁:看门狗 Lua 脚本实战

5. 告别手写接口文档!SpringBoot + Swagger3.0自动化方案

最新文章

随机文章