场景
项目有开发、测试、生产三个环境,每个环境的配置都不一样
一开始是把配置写在不同的application-{profile}.yml文件里,但是越来越多配置,管理起来很混乱
而且有时候会不小心把测试环境的配置提交到生产环境,挺危险的
所以决定统一管理配置
方案一:多Profile文件
这是最简单的方式,SpringBoot天然支持
配置文件结构
1 2 3 4 5
| src/main/resources/ ├── application.yml # 公共配置 ├── application-dev.yml # 开发环境 ├── application-test.yml # 测试环境 └── application-prod.yml # 生产环境
|
公共配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| spring: application: name: my-app
server: port: 8080
logging: level: root: INFO com.example: DEBUG pattern: console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
|
开发环境配置
1 2 3 4 5 6 7 8 9 10 11 12 13
| spring: datasource: url: jdbc:mysql://localhost:3306/dev_db username: root password: dev123456 redis: host: localhost port: 6379
logging: level: com.example: DEBUG
|
测试环境配置
1 2 3 4 5 6 7 8 9 10 11 12 13
| spring: datasource: url: jdbc:mysql://192.168.1.100:3306/test_db username: test password: test123456 redis: host: 192.168.1.101 port: 6379
logging: level: com.example: INFO
|
生产环境配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| spring: datasource: url: jdbc:mysql://prod-db.example.com:3306/prod_db username: ${DB_USERNAME} password: ${DB_PASSWORD} redis: host: ${REDIS_HOST} port: 6379
logging: level: root: WARN com.example: INFO file: name: /var/log/my-app/app.log
|
激活Profile
1 2 3 4 5 6 7
| java -jar my-app.jar --spring.profiles.active=prod
spring: profiles: active: dev
|
方案二:环境变量
对于敏感信息(如密码),建议使用环境变量:
1 2 3 4 5 6 7 8 9
| spring: datasource: url: jdbc:mysql://${DB_HOST}:3306/${DB_NAME} username: ${DB_USERNAME} password: ${DB_PASSWORD} redis: host: ${REDIS_HOST} password: ${REDIS_PASSWORD}
|
启动时设置环境变量:
1 2 3 4 5 6 7
| export DB_HOST=prod-db.example.com export DB_NAME=prod_db export DB_USERNAME=prod_user export DB_PASSWORD=secure_password export REDIS_HOST=redis.example.com
java -jar my-app.jar --spring.profiles.active=prod
|
或者:
1 2 3 4 5 6
| DB_HOST=prod-db.example.com \ DB_NAME=prod_db \ DB_USERNAME=prod_user \ DB_PASSWORD=secure_password \ REDIS_HOST=redis.example.com \ java -jar my-app.jar --spring.profiles.active=prod
|
方案三:外部配置文件
把配置文件放到jar包外部,方便修改:
1 2 3 4 5 6 7
| /opt/my-app/ ├── config/ │ ├── application.yml │ ├── application-dev.yml │ ├── application-test.yml │ └── application-prod.yml └── my-app.jar
|
启动时指定配置文件目录:
1
| java -jar /opt/my-app/my-app.jar --spring.config.location=file:/opt/my-app/config/
|
方案四:配置中心(推荐)
如果项目比较大,建议使用配置中心,比如Nacos、Apollo等
Nacos配置中心
添加依赖
1 2 3 4
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
|
配置bootstrap.yml
1 2 3 4 5 6 7 8 9 10 11 12 13
| spring: application: name: my-app cloud: nacos: config: server-addr: 127.0.0.1:8848 namespace: dev group: DEFAULT_GROUP file-extension: yml refresh-enabled: true profiles: active: dev
|
在Nacos中创建配置
在Nacos控制台创建配置文件:
- Data ID:
my-app-dev.yml
- Group:
DEFAULT_GROUP
- 配置内容:
1 2 3 4 5
| spring: datasource: url: jdbc:mysql://localhost:3306/dev_db username: root password: dev123456
|
动态刷新
使用@RefreshScope注解实现配置动态刷新:
1 2 3 4 5 6 7 8 9 10 11 12
| @RestController @RefreshScope public class ConfigController {
@Value("${custom.config:value}") private String config;
@GetMapping("/config") public String getConfig() { return config; } }
|
在Nacos控制台修改配置后,调用/actuator/refresh端点刷新:
1
| curl -X POST http://localhost:8080/actuator/refresh
|
Apollo配置中心
添加依赖
1 2 3 4 5
| <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>2.2.0</version> </dependency>
|
配置
1 2 3 4 5 6 7 8
| app: id: my-app
apollo: meta: http://192.168.1.100:8080 bootstrap: enabled: true namespaces: application,dev.mysql
|
使用
1 2 3 4 5 6 7 8
| @ApolloConfig private Config config;
@ApolloConfig("dev.mysql") private Config mysqlConfig;
@ApolloValue("${timeout:100}") private int timeout;
|
方案五:Spring Cloud Config
如果项目用Spring Cloud,可以用Spring Cloud Config
服务端
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
|
1 2 3 4 5 6 7
| @SpringBootApplication @EnableConfigServer public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }
|
1 2 3 4 5 6 7 8 9
| spring: cloud: config: server: git: uri: https://github.com/your-repo/config-repo username: your-username password: your-password search-paths: configs
|
客户端
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
|
1 2 3 4 5 6 7 8
| spring: application: name: my-app cloud: config: uri: http://config-server:8888 profile: dev label: main
|
配置加密
对于敏感配置,可以使用加密:
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>
|
生成密钥:
1 2
| keytool -genkeypair -alias mytestkey -keyalg RSA \ -keysize 2048 -keystore config-server.jks -validity 3650
|
配置:
1 2 3 4 5 6
| encrypt: key-store: location: classpath:config-server.jks alias: mytestkey password: changeme secret: changeme
|
加密配置:
1
| curl config-server:8888/encrypt -d "my-password"
|
在配置文件中使用:
1 2
| db: password: '{cipher}AQA8J...'
|
最佳实践
- 敏感信息用环境变量,不要写在配置文件里
- 每个环境独立的命名空间或分组
- 配置变更要走审批流程
- 定期更新密钥和密码
- 做好配置备份
- 配置文档化,说明每个配置项的作用
总结
配置管理很重要,好的配置管理能减少很多问题
建议:
- 小项目用多Profile文件 + 环境变量
- 大项目用配置中心(Nacos、Apollo)
- 敏感信息用环境变量或加密
- 配置变更要有流程和记录
暂时就先记录这么多