迁移到具有命名冲突的@ConfigurationProperties

时间:2019-05-15 05:46:00

标签: spring-boot kotlin configuration javabeans

我有一个带有application.properties文件的Spring Boot应用程序,看起来像这样:

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批注来读取这些值,因此字符串setting.mode的名称与“子设置”的前缀相同并不重要。 / p>

我承担了清理此应用程序的任务,并且我想转而将@ConfigurationProperties与匹配属性文件内容的大型配置对象一起使用,以使代码更易于使用。

我当时以为配置类的结构看起来像这样(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来消除此应用程序所有实例的命名问题)?

1 个答案:

答案 0 :(得分:0)

执行此操作的正确方法是 not 而不是拥有一个带有所有嵌套类的ConfigurationProperties类来构建整个结构,因为这意味着您不必要地填写了自己需要的部分知道将不会被使用,因为未注册其相应的bean。

执行此操作的最佳方法是像这样拆分配置类AB

@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定义以直接使用这些类,而不是调用整个配置对象:

@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)
}