Миграция в @ConfigurationProperties с конфликтами имен - PullRequest
0 голосов
/ 15 мая 2019

У меня есть приложение Spring Boot с файлом 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 с большим объектом конфигурации, который соответствует содержимому файла свойств, чтобы облегчить работу с кодом.

Я думал, что структура класса конфигурации будет выглядеть примерно так (пример 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
@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 голосов
/ 15 мая 2019

Правильный способ сделать это - , а не , чтобы иметь один ConfigurationProperties класс со всеми вложенными классами для построения всей структуры, потому что это означает, что вы излишне заполняете части, которые, как вы знаете, не будут использовать, потому что соответствующие им бобы не зарегистрированы.

Лучший способ сделать это - разделить классы конфигурации 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 для непосредственного использования этих классов вместо вызова всего объекта конфигурации:

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