迁移到带有命名冲突的@ConfigurationProperties
Migrating to @ConfigurationProperties with naming conflicts
我有一个 Spring 引导应用程序,其中 application.properties
文件如下所示:
setting.mode = a # Can be either `a` or `b`
setting.mode.a.subsetting1 = abc
setting.mode.a.subsetting2 = def
setting.mode.b.subsetting1 = ghi
setting.mode.b.subsetting2 = jkl
我们曾经使用@Value
注解来读取这些值,所以String setting.mode
的名称与"sub-settings"的前缀相同并不重要.
我接到了清理此应用程序的任务,我想转而使用 @ConfigurationProperties
和与属性文件内容匹配的大型配置对象,以使代码更易于工作与.
我在想配置的结构 class 看起来像这样(Kotlin 示例,但没关系):
@Component
@ConfigurationProperties("setting")
class MyProperties {
// Has the value either `a` or `b` to tell us which component to use
lateinit var mode: String
// THE PROBLEM IS HERE
// -------------------
//
// The two classes below need to be under the `mode`
// prefix, but they can't be because it is already used
// to get its String value above.
val a = A()
val b = B()
class A {
lateinit var subsetting1: String
lateinit var subsetting2: String
}
class B {
lateinit var subsetting1: String
lateinit var subsetting2: String
}
}
注意setting.mode
的值也用来决定注册哪个bean:
@Bean
@ConditionalOnProperty(name = ["setting.mode"], havingValue = "a")
fun a(properties: MyProperties): CommonInterface {
return A(properties.mode.a)
}
@Bean
@ConditionalOnProperty(name = ["setting.mode"], havingValue = "b")
fun b(properties: MyProperties): CommonInterface {
return B(properties.mode.b)
}
如何设置此配置(无需重写 application.properties
来消除此应用程序所有实例的命名问题)?
正确的做法是 而不是 使用一个 ConfigurationProperties
class 和所有嵌套的 classes 来构建整个结构,因为这意味着您不必要地填充了您知道不会使用的部分,因为它们的相应 bean 未注册。
最好的方法是像这样拆分配置 classes A
和 B
:
@Component
@ConfigurationProperties("setting.mode.a")
class AProperties {
lateinit var subsetting1: String
lateinit var subsetting2: String
}
@Component
@ConfigurationProperties("setting.mode.b")
class BProperties {
lateinit var subsetting1: String
lateinit var subsetting2: String
}
然后更改 @Bean
定义以直接使用这些 classes 而不是调用整个配置对象:
@Bean
@ConditionalOnProperty(name = ["setting.mode"], havingValue = "a")
fun a(properties: AProperties): CommonInterface {
return A(properties)
}
@Bean
@ConditionalOnProperty(name = ["setting.mode"], havingValue = "b")
fun b(properties: BProperties): CommonInterface {
return B(properties)
}
我有一个 Spring 引导应用程序,其中 application.properties
文件如下所示:
setting.mode = a # Can be either `a` or `b`
setting.mode.a.subsetting1 = abc
setting.mode.a.subsetting2 = def
setting.mode.b.subsetting1 = ghi
setting.mode.b.subsetting2 = jkl
我们曾经使用@Value
注解来读取这些值,所以String setting.mode
的名称与"sub-settings"的前缀相同并不重要.
我接到了清理此应用程序的任务,我想转而使用 @ConfigurationProperties
和与属性文件内容匹配的大型配置对象,以使代码更易于工作与.
我在想配置的结构 class 看起来像这样(Kotlin 示例,但没关系):
@Component
@ConfigurationProperties("setting")
class MyProperties {
// Has the value either `a` or `b` to tell us which component to use
lateinit var mode: String
// THE PROBLEM IS HERE
// -------------------
//
// The two classes below need to be under the `mode`
// prefix, but they can't be because it is already used
// to get its String value above.
val a = A()
val b = B()
class A {
lateinit var subsetting1: String
lateinit var subsetting2: String
}
class B {
lateinit var subsetting1: String
lateinit var subsetting2: String
}
}
注意setting.mode
的值也用来决定注册哪个bean:
@Bean
@ConditionalOnProperty(name = ["setting.mode"], havingValue = "a")
fun a(properties: MyProperties): CommonInterface {
return A(properties.mode.a)
}
@Bean
@ConditionalOnProperty(name = ["setting.mode"], havingValue = "b")
fun b(properties: MyProperties): CommonInterface {
return B(properties.mode.b)
}
如何设置此配置(无需重写 application.properties
来消除此应用程序所有实例的命名问题)?
正确的做法是 而不是 使用一个 ConfigurationProperties
class 和所有嵌套的 classes 来构建整个结构,因为这意味着您不必要地填充了您知道不会使用的部分,因为它们的相应 bean 未注册。
最好的方法是像这样拆分配置 classes A
和 B
:
@Component
@ConfigurationProperties("setting.mode.a")
class AProperties {
lateinit var subsetting1: String
lateinit var subsetting2: String
}
@Component
@ConfigurationProperties("setting.mode.b")
class BProperties {
lateinit var subsetting1: String
lateinit var subsetting2: String
}
然后更改 @Bean
定义以直接使用这些 classes 而不是调用整个配置对象:
@Bean
@ConditionalOnProperty(name = ["setting.mode"], havingValue = "a")
fun a(properties: AProperties): CommonInterface {
return A(properties)
}
@Bean
@ConditionalOnProperty(name = ["setting.mode"], havingValue = "b")
fun b(properties: BProperties): CommonInterface {
return B(properties)
}