如何替换application.properties配置,以代码或Bean形式统一管理?
解决Spring Boot配置全代码化的通用方案
团队配置管理约定
我们团队要求所有配置都通过代码形式管理(例如定义AppConfiguration类),示例如下:
@Value("${spring.datasource.url:jdbc:postgresql://localhost:5432/postgres}") private String jdbcUrl;
随后使用这些配置值定义Bean:
@Bean @Primary @ConfigurationProperties(prefix = "spring.datasource.configuration") public DataSource teamDataSource() { return dataSourceProperties().initializeDataSourceBuilder().build(); } @Bean @Primary public DataSourceProperties telemetryControlServiceDataSourceProperties() { DataSourceProperties dataSourceProperties = new DataSourceProperties(); dataSourceProperties.setUrl(appConfig.getJdbcUrl()); // 其他配置设置 return dataSourceProperties; }
问题描述
随着配置项增多,按团队约定不能再使用application.properties文件,但有时找不到对应@ConfigurationProperties的POJO类。有没有通用方法能把application.properties里的所有配置项都以代码/Bean形式暴露?比如Actuator的部分配置能找到对应POJO,但大部分找不到,示例配置如下:
management.endpoints.web.base-path=/debug management.endpoints.web.exposure.include=* management.endpoints.web.exposure.exclude=env,beans management.endpoint.health.show-details=always management.endpoint.metrics.enabled=true management.endpoint.prometheus.enabled=true management.endpoint.loggers.enabled=true
可行解决方案
1. 自定义通用配置映射类
创建一个通用配置类,通过@ConfigurationProperties的宽松绑定特性,将前缀设为空字符串,就能映射所有配置项。如果需要结构化管理,还可以嵌套内部类对应配置层级,示例如下:
@Configuration @ConfigurationProperties(prefix = "") public class AllProperties { // 全局配置映射,适合零散配置 private Map<String, Object> properties = new HashMap<>(); // 结构化映射Actuator配置 private Management management; // Getter & Setter public Map<String, Object> getProperties() { return properties; } public void setProperties(Map<String, Object> properties) { this.properties = properties; } public Management getManagement() { return management; } public void setManagement(Management management) { this.management = management; } // 内部类对应management层级 public static class Management { private Endpoints endpoints; private Endpoint endpoint; // Getter & Setter public Endpoints getEndpoints() { return endpoints; } public void setEndpoints(Endpoints endpoints) { this.endpoints = endpoints; } public Endpoint getEndpoint() { return endpoint; } public void setEndpoint(Endpoint endpoint) { this.endpoint = endpoint; } public static class Endpoints { private Web web; public Web getWeb() { return web; } public void setWeb(Web web) { this.web = web; } public static class Web { private String basePath; private Exposure exposure; public String getBasePath() { return basePath; } public void setBasePath(String basePath) { this.basePath = basePath; } public Exposure getExposure() { return exposure; } public void setExposure(Exposure exposure) { this.exposure = exposure; } public static class Exposure { private String include; private String exclude; public String getInclude() { return include; } public void setInclude(String include) { this.include = include; } public String getExclude() { return exclude; } public void setExclude(String exclude) { this.exclude = exclude; } } } } public static class Endpoint { private Health health; private Metrics metrics; private Prometheus prometheus; private Loggers loggers; public Health getHealth() { return health; } public void setHealth(Health health) { this.health = health; } public Metrics getMetrics() { return metrics; } public void setMetrics(Metrics metrics) { this.metrics = metrics; } public Prometheus getPrometheus() { return prometheus; } public void setPrometheus(Prometheus prometheus) { this.prometheus = prometheus; } public Loggers getLoggers() { return loggers; } public void setLoggers(Loggers loggers) { this.loggers = loggers; } public static class Health { private String showDetails; public String getShowDetails() { return showDetails; } public void setShowDetails(String showDetails) { this.showDetails = showDetails; } } public static class Metrics { private boolean enabled; public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } public static class Prometheus { private boolean enabled; public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } public static class Loggers { private boolean enabled; public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } } } }
使用时直接注入AllProperties,就能获取所有配置项,结构化的Actuator配置也能通过allProperties.getManagement()层级访问。
2. 用Spring Boot配置元数据生成工具辅助
Spring Boot提供的spring-boot-configuration-processor依赖可以帮你快速生成配置类:
- 先临时把需要的配置项写入
application.properties - 添加依赖后,工具会自动生成配置元数据
- 借助IDE(如IntelliJ IDEA)的自动生成功能,直接根据元数据创建对应POJO
添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
3. 复用Spring Boot内置配置类
很多Spring Boot组件的配置都有官方内置的POJO类,只是需要找对路径:
management.endpoints.web.*对应org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointPropertiesmanagement.endpoint.health.*对应org.springframework.boot.actuate.autoconfigure.health.HealthEndpointPropertiesmanagement.endpoint.metrics.*对应org.springframework.boot.actuate.autoconfigure.metrics.MetricsEndpointProperties
可以直接注入这些类,或者自定义Bean覆盖默认配置,示例:
@Configuration public class ActuatorConfig { @Bean @Primary public WebEndpointProperties webEndpointProperties() { WebEndpointProperties properties = new WebEndpointProperties(); properties.setBasePath("/debug"); WebEndpointProperties.Exposure exposure = new WebEndpointProperties.Exposure(); exposure.setInclude(Collections.singletonList("*")); exposure.setExclude(Arrays.asList("env", "beans")); properties.setExposure(exposure); return properties; } @Bean @Primary public HealthEndpointProperties healthEndpointProperties() { HealthEndpointProperties properties = new HealthEndpointProperties(); properties.setShowDetails(HealthEndpointProperties.ShowDetails.ALWAYS); return properties; } // 其他Actuator配置类同理实现 }
内容的提问来源于stack exchange,提问作者Kostov
相关产品推荐
相关产品推荐

