Spring Boot配置覆盖异常:应用YAML无法覆盖依赖库Properties
问题描述
我的Spring Boot应用版本为2.6.12,依赖了一个版本为2.7.11的Spring Boot库,该库包含以下内容:
自动配置类
@Configuration @EnableConfigurationProperties({LibProperties.class}) public class LibAutoConfiguration { public LibAutoConfiguration() { } @Bean( initMethod = "checkSomething", destroyMethod = "release" ) SomeHandler someHandler(LibProperties properties, ShutdownManager shutdownManager) { return new SomeHandler (properties, shutdownManager); } @Bean ShutdownManager shutdownManager(ApplicationContext applicationContext) { return new ShutdownManager(applicationContext); } }
属性配置类
@ConfigurationProperties("lib") @ConstructorBinding public class LibProperties { private final int a; private final String b; public LibProperties(int a, String b) { this.a = a; this.b = b; } // getters }
spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.lib.config.LibAutoConfiguration
该库的classpath下还有一个application.properties文件,其中属性值为空:
lib.a= lib.b=
我的应用启动类:
@SpringBootApplication(scanBasePackages = { "com.myApp" }) public class Application { public static void main(String[] args) { // 业务代码 } }
应用classpath下的application.yml已配置好LibProperties的所有属性:
lib: a: 100 b: "test-value"
但应用启动失败,报错如下:
Failed to bind properties under 'lib.a' to int: Property: lib.a Value: "" Origin: class path resource [application.properties] from myApp.jar!/BOOT-INF/lib/lib.jar - 6:0 Reason: failed to convert java.lang.String to int (caused by java.lang.IllegalArgumentException: A null value cannot be assigned to a primitive type) Action: Update your application's configuration
可见应用的YAML配置并未覆盖依赖库的Properties配置,仍读取库中打包的空值。但将应用配置改为.properties文件,或使用--spring.config.location加载YAML文件时,该问题不会出现。
请问导致此问题的根本原因是什么?我预期应用打包的YAML文件应能覆盖依赖库的Properties配置。
根本原因分析
这是Spring Boot配置加载逻辑与@ConstructorBinding特性结合引发的问题,具体细节如下:
- 配置源类型与加载顺序的差异
Spring Boot中,.properties和.yml属于不同类型的配置源,它们的加载合并逻辑有区别:
- 同类型配置源(比如两个
.properties文件)会按优先级合并,应用自身的配置会覆盖依赖库的配置; - 不同类型的配置源(
.properties和.yml)会被视为独立源,加载顺序和合并时机受绑定阶段影响。
@ConstructorBinding的早期绑定特性
使用@ConstructorBinding的配置类,属性绑定发生在Spring上下文刷新之前的早期初始化阶段:
- 依赖库中的
application.properties会被优先加载,其中lib.a=被解析为空字符串,绑定到int类型字段时直接触发类型转换异常; - 应用的
.yml配置虽然优先级更高,但由于绑定时机过早,此时.yml的配置还未被合并到当前属性源中,无法覆盖依赖库的空值。
- 其他可行方式的原因
- 应用使用
.properties文件时,同类型配置源按优先级合并,应用的有效值会覆盖依赖库的空值,绑定过程正常; - 使用
--spring.config.location加载YAML文件时,该配置源的优先级远高于classpath下的所有配置文件,会在早期绑定阶段就被加载生效,从而覆盖依赖库的空值。
内容的提问来源于stack exchange,提问作者D.Razvan
相关产品推荐
相关产品推荐

