Spring (не загрузка) загружает несколько файлов yml из нескольких проектов

Поэтому я прочитал множество статей о том, как настроить загрузку Spring так, чтобы она знала о большем количестве файлов yml, чем application.yml, и как их включить — даже из подпроектов. Однако трудно найти статьи, описывающие то же самое для «чистого» Spring. Однако я думаю, что я иду в правильном направлении, я просто не могу вернуть свои значения конфигурации.

Это простая многопроектная сборка Gradle с двумя проектами для простоты. Один проект является "главным" весенним проектом - т.е. Spring Context инициализируется в этом проекте. Другой — это «поддерживающий» модуль с некоторыми сущностями базы данных и конфигурацией источника данных. Мы используем конфигурацию на основе аннотаций.

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

Этот пост SA дал мне довольно далеко разные ссылки в разных ответах и ​​составление моего решения из этого. Структура и код следующие:

mainproject
  src
    main
      groovy
        Application.groovy
    resourcers
      application.yml

submodule
  src
    main
      groovy
        PropertiesConfiguration.groovy
        DataSource.groovy
    resources
      datasource.yml

PropertiesConfiguration.groovy добавляет datasource.yml с помощью PropertySourcesPlaceholderConfigurer:

@Configuration
class PropertiesConfiguration {

    @Bean
    public PropertySourcesPlaceholderConfigurer configure() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer()
        YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean()
        yamlPropertiesFactoryBean.setResources(new ClassPathResource("datasource.yml"))
        configurer.setProperties(yamlPropertiesFactoryBean.getObject())
        return configurer
    }
}

Затем Datasource.groovy должен считывать значения на основе профиля пружины, используя (код уменьшен для удобочитаемости):

@Autowired
Environment env

datasource.username = env.getProperty("datasource.username")

env.getProperty возвращает ноль. Независимо от того, какой профиль пружины активен. Я могу получить доступ к значению конфигурации с помощью аннотации @Value, однако тогда активный профиль не соблюдается и возвращает значение, даже если оно не определено для этого профиля. Мой yml выглядит (что-то) так:

---
spring:
  profiles: development

datasource:
  username: sa
  password:
  databaseUrl: jdbc:h2:mem:tests
  databaseDriver: org.h2.Driver

Я могу из Application.groovy проверить мой ApplicationContext с помощью отладчика и подтвердить, что мой PropertySourcesPlaceholderConfigurer существует и значения загружены. Осмотр applicationContext.environment.propertySources его НЕТ.

Что мне не хватает?


person Hoof    schedule 02.03.2018    source источник


Ответы (1)


Использование PropertySourcesPlaceholderConfigurer не добавляет свойства к Environment. Использование чего-то вроде @PropertySource("classpath:something.properties") на уровне класса вашего класса конфигурации добавит свойства к Environment, но, к сожалению, это не работает с yaml-файлами.

Таким образом, вам придется вручную добавить свойства, считанные из файла yaml, в ваш файл Environment. Вот один из способов сделать это:

@Bean
public PropertySourcesPlaceholderConfigurer config(final ConfigurableEnvironment confenv) {
    final PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
    final YamlPropertiesFactoryBean yamlProperties = new YamlPropertiesFactoryBean();
    yamlProperties.setResources(new ClassPathResource("datasource.yml"));
    configurer.setProperties(yamlProperties.getObject());

    confenv.getPropertySources().addFirst(new PropertiesPropertySource("datasource", yamlProperties.getObject()));

    return configurer;
}

С помощью этого кода вы можете внедрять свойства любым из этих двух способов:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PropertiesConfiguration.class)
public class ConfigTest {

    @Autowired
    private Environment environment;

    @Value("${datasource.username}")
    private String username;

    @Test
    public void props() {
        System.out.println(environment.getProperty("datasource.username"));
        System.out.println(username);
    }
}

Со свойствами, указанными в вопросе, это напечатает «sa» два раза.

Редактировать: не похоже, что PropertySourcesPlaceholderConfigurer сейчас действительно нужен, поэтому код можно упростить до приведенного ниже и по-прежнему получать тот же результат.

@Autowired
public void config(final ConfigurableEnvironment confenv) {
    final YamlPropertiesFactoryBean yamlProperties = new YamlPropertiesFactoryBean();
    yamlProperties.setResources(new ClassPathResource("datasource.yml"));

    confenv.getPropertySources().addFirst(new PropertiesPropertySource("datasource", yamlProperties.getObject()));
}

Редактировать 2:

Теперь я вижу, что вы хотите использовать файл yaml с несколькими документами в одном файле и выбор стиля загрузки Spring по профилю. Невозможно использовать обычный Spring. Поэтому я думаю, что вам нужно разделить ваши файлы yaml на несколько с именами «источник данных-{профиль}.yml». Затем это должно работать (возможно, с более сложной проверкой нескольких профилей и т. д.)

@Autowired
public void config(final ConfigurableEnvironment confenv) {
    final YamlPropertiesFactoryBean yamlProperties = new YamlPropertiesFactoryBean();

    yamlProperties.setResources(new ClassPathResource("datasource-" + confenv.getActiveProfiles()[0] + ".yml"));

    confenv.getPropertySources().addFirst(new PropertiesPropertySource("datasource", yamlProperties.getObject()));
}

Редактировать 3:

Также можно было бы использовать функциональность из загрузки Spring без полного преобразования вашего проекта (хотя я на самом деле не пробовал это в реальном проекте). Добавив зависимость к org.springframework.boot:spring-boot:1.5.9.RELEASE, я смог заставить его работать с одним datasource.yml и несколькими профилями, например:

@Autowired
public void config (final ConfigurableEnvironment confenv) {
    final YamlPropertySourceLoader yamlPropertySourceLoader = new YamlPropertySourceLoader();
    try {
        final PropertySource<?> datasource =
                yamlPropertySourceLoader.load("datasource",
                                            new ClassPathResource("datasource.yml"),
                                            confenv.getActiveProfiles()[0]);
        confenv.getPropertySources().addFirst(datasource);
    } catch (final IOException e) {
        throw new RuntimeException("Failed to load datasource properties", e);
    }
}
person Tobb    schedule 02.03.2018
comment
Это работает - немного. Активный профиль Spring не принимается во внимание, и всегда возвращается последнее значение в файле yml. Несмотря на то, что он содержится в другом блоке пружинных профилей. Это только загрузка Spring или она должна работать? - person Hoof; 02.03.2018
comment
Я думаю, что это будет специфично для весенней загрузки. Я думаю, что в обычном Spring было бы более распространено хранить свойства в отдельных файлах. - person Tobb; 02.03.2018