Spring(不开机)从多个项目加载多个yml文件

Spring (not boot) load multiple yml files from multiple projects

所以我阅读了关于如何配置 Spring 引导以识别比 application.yml 更多的 yml 文件以及如何包含这些文件的 dosens af 文章——甚至来自子项目。然而,很难找到描述 "pure" Spring 的文章。但是我认为我正朝着正确的方向前进,我只是无法取回我的配置值。

这是一个直接的多项目 gradle 构建 - 为简单起见 - 两个项目。一个项目是 "main" spring 项目 - 即。 Spring 上下文已在此项目中初始化。另一个是带有一些数据库实体和数据源配置的 "support" 模块。我们使用基于注释的配置。

我希望能够在支持模块中定义一组配置属性,并根据任何 spring 配置文件处于活动状态,相应地加载数据源配置。

SA post 跟随不同答案中的不同链接让我走了很远,并由此构成了我的解决方案。结构及代码如下:

mainproject
  src
    main
      groovy
        Application.groovy
    resourcers
      application.yml

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

PropertiesConfiguration.groovy 使用 PropertySourcesPlaceholderConfigurer 添加 datasource.yml:

@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 应该读取基于 spring 配置文件的值,使用(为便于阅读而减少代码):

@Autowired
Environment env

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

env.getProperty return 为空。无论什么 spring 配置文件处于活动状态。我可以使用 @Value 批注访问配置值,但是活动配置文件不受尊重,它 return 一个值,即使它没有为该配置文件定义。我的 yml 看起来像这样:

---
spring:
  profiles: development

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

我可以从 Application.groovy 使用调试器检查我的 ApplicationContext 并确认我的 PropertySourcesPlaceholderConfigurer 存在并且值已加载。检查 applicationContext.environment.propertySources 它不存在。

我错过了什么?

使用 PropertySourcesPlaceholderConfigurer 不会向 Environment 添加属性。在配置 class 的 class 级别上使用类似 @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-file 与一个文件中的多个文档一起使用,并且 Spring boot-style 按配置文件选择。使用常规 Spring 似乎是不可能的。所以我认为你必须将你的 yaml 文件分成几个,命名为 "datasource-{profile}.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);
    }
}