SpringBoot Kotlin读取application.yaml变量报错:lateinit属性未初始化
你碰到的这个lateinit property has not been initialized错误,核心原因是Spring的@ConfigurationProperties机制无法自动注入伴生对象(companion object)里的静态属性,让我给你拆解一下:
问题根源
Spring的@ConfigurationProperties是专门用来绑定配置到类的实例属性上的,而companion object属于类的静态成员范畴——Spring容器只会处理类的实例属性的注入,完全不会识别或处理静态属性。
你把value和result放在companion object里,当Spring初始化NumError这个Bean的时候,只会扫描类的非静态属性并绑定配置值,伴生对象里的变量根本不会被触及,所以这些lateinit变量一直处于未初始化状态,调用时自然就抛出kotlin.UninitializedPropertyAccessException了。
正确的解决方式
方式1:遵循Spring设计规范(推荐)
去掉companion object,直接把配置属性定义为类的实例属性,然后通过依赖注入的方式访问:
@ConfigurationProperties(prefix = "num_error") @Component class NumError { lateinit var value: String lateinit var result: Number }
在需要使用的地方,通过构造注入获取NumError的实例:
@Service class YourBusinessService( // 构造注入NumError实例 private val numError: NumError ) { fun someBusinessLogic() { println("配置的value是:${numError.value}") println("配置的result是:${numError.result}") } }
这种方式完全符合Spring的依赖注入设计,代码更易测试、维护,也不会有静态变量带来的潜在问题。
方式2:特殊场景下的静态访问(不推荐)
如果因为某些历史原因必须用静态方式访问配置,可以通过@PostConstruct注解,在Bean初始化完成后手动把实例属性的值赋值给伴生对象的静态变量:
@ConfigurationProperties(prefix = "num_error") @Component class NumError { // 实例属性,用于Spring绑定配置 lateinit var value: String lateinit var result: Number companion object { // 静态变量,供外部静态访问 lateinit var staticValue: String lateinit var staticResult: Number } // Bean初始化完成后执行,把实例属性的值同步到静态变量 @PostConstruct fun syncStaticProperties() { staticValue = this.value staticResult = this.result } }
之后你就可以通过NumError.staticValue来访问配置值了,但这种方式会破坏依赖注入的封装性,尽量少用。
内容的提问来源于stack exchange,提问作者has400

