Привязка нескольких приложений.yml из рабочего каталога в ConfigurationProperties

#spring #spring-boot

#весна #пружинный ботинок

Вопрос:

Начиная с Spring Boot 2.4.0, из того, что я почерпнул из справочной документации, я должен иметь возможность привязывать несколько application.yaml файлов из рабочего каталога к ConfigurationProperties :

Расположение подстановочных знаков особенно полезно в такой среде, как Kubernetes, когда существует несколько источников свойств конфигурации.

Например, если у вас есть некоторая конфигурация Redis и некоторая конфигурация MySQL, вы можете захотеть сохранить эти две части конфигурации отдельно, требуя при этом, чтобы обе они присутствовали в файле application.properties. Это может привести к тому, что два отдельных файла application.properties будут смонтированы в разных местах, таких как /config/redis/application.properties и /config/mysql/application.properties . В таком случае наличие подстановочного знака config/*/ приведет к обработке обоих файлов.

По умолчанию Spring Boot включает config/*/ в места поиска по умолчанию. Это означает, что будет произведен поиск во всех подкаталогах каталога /config за пределами вашего jar.

Насколько я понимаю, следующий тестовый пример показывает, что это работает не так, как описано:

Иерархия проекта:

 config/
  first/
    application.yaml
  second/
    application.yaml
src/
  main/
    kotlin/
      test/
        Application.kt
  test/
    kotlin/
      test/
        TestCase.kt
 

config/first/application.yaml

 composite:
  from-first-file:
    it: works
 

config/second/application.yaml

 composite:
  from-second-file:
    it: works
 

src/main/kotlin/test/Application.kt

 @SpringBootApplication(proxyBeanMethods = false)
@EnableConfigurationProperties(CompositeProperties::class)
class Application

fun main(vararg args: String) {
    runApplication<Application>(*args)
}

@ConstructorBinding
@ConfigurationProperties("composite")
data class CompositeProperties(
    val fromFirstFile: Map<String, String> = mapOf(),
    val fromSecondFile: Map<String, String> = mapOf()
)
 

src/test/kotlin/test/TestCase.kt

 @SpringBootTest
class TestCase {

    @Autowired
    private lateinit var compositeProperties: CompositeProperties

    @Test
    fun `first file is bound to configuration properties`() {
        assertThat(compositeProperties.fromFirstFile).containsEntry("it", "works")
    }

    @Test
    fun `second file is bound to configuration properties`() {
        assertThat(compositeProperties.fromSecondFile).containsEntry("it", "works")
    }
}
 

Первый тест пройден, второй не выполняется. Я попробовал несколько вариантов, чтобы исключить крайние случаи, и похоже, что второй файл полностью пропущен. Например, я попытался установить значение spring.application.name во втором файле, и оно также не учитывается.

Если это действительно ошибка, есть ли обходной путь, который я мог бы использовать, пока это не будет исправлено?

Комментарии:

1. Можете ли вы попробовать config каталог внутри /src/main ?

2. Я просто предполагаю, но может ли такое поведение быть связано с тем, что spring не объединяет деревья свойств. т.е. если у вас было два ConfigurationProperties класса, которые загружали разные деревья yaml базового уровня — composite1 и composite2, это работает?

3. конфигурация должна находиться в каталоге рядом с вашим файлом jar, поскольку вы не используете файл jar, это правило не применяется.

4. @Steephen Я мог бы, но какой в этом смысл, поскольку это вообще не мое требование? В любом случае, ничто не привязывается при выполнении того, что вы предлагаете

5. @HopeyOne Как упоминалось в OP, я попытался добавить другое свойство ко второму файлу, и оно также не привязано, так что это должно дать нам четкий намек на то, что ваше предложение не сработает; и действительно, это не так

Ответ №1:

Как я и подозревал, это ошибка в 2.4.0. Пока проблема не будет устранена, ее можно обойти, установив spring.config.use-legacy-processing=true .