【问题标题】:Migrating to @ConfigurationProperties with naming conflicts迁移到有命名冲突的 @ConfigurationProperties
【发布时间】:2019-10-02 04:34:32
【问题描述】:

我有一个带有 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的String名称与“子设置”的前缀相同并不重要。

我的任务是清理此应用程序,我想转而使用 @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 以消除此应用程序所有实例的命名问题)?

【问题讨论】:

    标签: spring-boot kotlin configuration javabeans


    【解决方案1】:

    做到这一点的正确方法是拥有一个包含所有嵌套类的单个 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)
    }
    

    【讨论】:

      猜你喜欢
      • 2017-01-24
      • 2013-06-02
      • 2016-08-07
      • 1970-01-01
      • 2019-01-07
      • 2015-12-08
      • 2019-11-23
      • 2020-10-05
      • 1970-01-01
      相关资源
      最近更新 更多