SpringBoot Profiles多环境管理
Spring Boot 简化了配置,但日志管理依然需要重视。日志配置、链路追踪、排查思路都是日常开发中会遇到的问题。本文讲实际项目中的日志管理经验。
Profile 配置方式
#
1. 配置文件命名
src/main/resources/ ├── application.yml # 公共配置 ├── application-dev.yml # 开发环境 ├── application-test.yml # 测试环境 └── application-prod.yml # 生产环境
|
#
2. 激活 Profile
spring: profiles: active: dev
|
java -jar app.jar --spring.profiles.active=prod
export SPRING_PROFILES_ACTIVE=prod
|
#
3. Profile 组(Spring Boot 2.4+)
spring: profiles: group: local: - dev - local-db - local-cache production: - prod - prod-db - prod-cache - monitoring
|
java -jar app.jar --spring.profiles.active=production
|
@Profile 注解
#
Bean 级别
@Configuration public class DataSourceConfig { @Bean @Profile("dev") public DataSource devDataSource() { return DataSourceBuilder.create() .url("jdbc:h2:mem:testdb") .build(); } @Bean @Profile("prod") public DataSource prodDataSource() { return DataSourceBuilder.create() .url("jdbc:mysql://prod:3306/db") .build(); } @Bean @Profile("!prod") public MockService mockService() { return new MockService(); } }
|
#
配置类级别
@Profile("dev") @Configuration public class DevConfig { @PostConstruct public void init() { System.out.println("开发环境配置加载"); } }
@Profile("prod") @Configuration public class ProdConfig { @Bean public SecurityConfig securityConfig() { return new SecurityConfig(); } }
|
#
多 Profile
@Profile({"dev", "test"}) @Component public class DebugInterceptor implements HandlerInterceptor { }
|
Profile 条件化配置
#
@ConditionalOnProperty
@Component @ConditionalOnProperty(prefix = "feature", name = "new-ui", havingValue = "true") public class NewUIService { }
@Component @ConditionalOnProperty(prefix = "feature", name = "new-ui", matchIfMissing = true) public class DefaultUIService { }
|
#
配置属性
feature: new-ui: true cache: false
feature: new-ui: false cache: true
|
环境特定配置
#
开发环境
spring: datasource: url: jdbc:h2:mem:testdb driver-class-name: org.h2.Driver jpa: hibernate: ddl-auto: create-drop show-sql: true
logging: level: com.example: DEBUG org.hibernate.SQL: DEBUG
|
#
测试环境
spring: datasource: url: jdbc:mysql://test-db:3306/test_db username: test password: test redis: host: test-redis
server: port: 8081
|
#
生产环境
spring: datasource: url: jdbc:mysql://prod-db:3306/prod_db username: ${DB_USERNAME} password: ${DB_PASSWORD} hikari: maximum-pool-size: 50 minimum-idle: 10 jpa: hibernate: ddl-auto: none show-sql: false
logging: level: root: WARN com.example: INFO
|
获取当前 Profile
@Component public class ProfileChecker implements EnvironmentAware { private Environment environment; @Override public void setEnvironment(Environment environment) { this.environment = environment; } public void checkProfile() { boolean isDev = environment.acceptsProfiles(Profiles.of("dev")); String[] activeProfiles = environment.getActiveProfiles(); boolean isProdOrTest = environment.acceptsProfiles(Profiles.of("prod", "test")); System.out.println("当前环境: " + String.join(", ", activeProfiles)); } }
|
Profile 与配置优先级
优先级从高到低:
1. 命令行参数: --server.port=9000 2. Java 系统属性: -Dserver.port=9000 3. 环境变量: SERVER_PORT=9000 4. application-{profile}.properties/yml 5. application.properties/yml 6. @PropertySource 7. SpringApplication.setDefaultProperties
|
配置加密
jasypt: encryptor: password: ${JASYPT_PASSWORD}
spring: datasource: password: ENC(encrypted_value_here)
|
@Configuration public class JasyptConfig { @Bean("jasyptStringEncryptor") public StringEncryptor stringEncryptor() { PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); SimpleStringPBEConfig config = new SimpleStringPBEConfig(); config.setPassword(System.getenv("JASYPT_PASSWORD")); config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256"); config.setPoolSize(1); encryptor.setConfig(config); return encryptor; } }
|
测试中使用 Profile
@SpringBootTest @ActiveProfiles("test") class MyIntegrationTest { }
@SpringBootTest @ActiveProfiles({"test", "no-security"}) class MyControllerTest { }
|
容器化部署
#
Dockerfile
FROM openjdk:17-jdk-slim COPY target/app.jar app.jar ENTRYPOINT ["java", "-Dspring.profiles.active=${PROFILE}", "-jar", "/app.jar"]
|
#
Docker Compose
version: '3' services: app: image: myapp:latest environment: - SPRING_PROFILES_ACTIVE=prod - DB_USERNAME=root - DB_PASSWORD=secret
|
#
Kubernetes
apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - name: app image: myapp:latest env: - name: SPRING_PROFILES_ACTIVE value: "prod" - name: DB_USERNAME valueFrom: secretKeyRef: name: db-secret key: username
|
最佳实践
| 实践 |
说明 |
| 默认配置 |
application.yml 放公共配置 |
| 环境配置 |
application-{env}.yml 放环境差异 |
| 敏感信息 |
使用环境变量或配置中心 |
| 本地开发 |
使用 H2 / 内存中间件 |
| 生产环境 |
关闭调试日志,启用监控 |
| 配置验证 |
启动时验证必要配置是否存在 |
总结
Spring Profiles 提供了灵活的环境管理能力:
- 配置文件分离:application-{profile}.yml
- 条件化 Bean:@Profile 注解
- Profile 组:组合多个 profile
- 优先级:命令行 > 环境变量 > profile 配置 > 默认配置
合理使用 Profile,可以让应用在不同环境间无缝切换。
核心要点
日志级别设置:根据环境设置合适的级别
日志格式配置:添加 traceId 便于链路追踪
日志输出:控制台输出和文件输出的配置
日志归档:设置滚动策略和保留时间
总结
日志是排查问题的生命线,合理配置日志可以提升排查效率。在实际项目中,结合 ELK 等工具搭建日志系统,可以更好地管理和分析日志。