【问题标题】:Spring (not boot) load multiple yml files from multiple projectsSpring(不启动)从多个项目加载多个 yml 文件
【发布时间】:2018-08-10 14:22:53
【问题描述】:

所以我已经阅读了关于如何配置 Spring boot 以了解比 application.yml 更多的 yml 文件以及如何包含这些文件的文章 - 甚至来自子项目。然而,很难找到描述“纯” Spring 相同的文章。但是我认为我正朝着正确的方向前进,我只是无法恢复我的配置值。

这是一个简单的多项目 gradle 构建,为简单起见,有两个项目。一个项目是“主要”春季项目 - 即。 Spring Context 在这个项目中被初始化。另一个是带有一些数据库实体和数据源配置的“支持”模块。我们使用基于注解的配置。

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

This SA 帖子让我非常关注不同答案中的不同链接,并由此构成我的解决方案。结构和代码如下:

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 应使用基于弹簧配置文件的值读取值(代码减少以提高可读性):

@Autowired
Environment env

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

env.getProperty 返回 null。无论何种弹簧轮廓处于活动状态。我可以使用 @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 它不存在。

我错过了什么?

【问题讨论】:

    标签: java spring spring-profiles spring-properties


    【解决方案1】:

    使用PropertySourcesPlaceholderConfigurer 不会向Environment 添加属性。在配置类的类级别上使用@PropertySource("classpath:something.properties") 之类的东西会将属性添加到Environment,但遗憾的是这不适用于yaml-files。

    因此,您必须手动将从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 文件分成几个,命名为“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 boot 中的功能(虽然我实际上还没有在真实项目中尝试过)。通过向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);
        }
    }
    

    【讨论】:

    • 它工作 - 有点。不考虑活动弹簧配置文件,始终返回 yml 文件中的最后一个值。即使它包含在不同的弹簧型材块下。这只是 Spring Boot 的事情还是应该起作用?
    • 我认为那将是特定于 Spring Boot 的。对于常规的 Spring,我认为将属性保存在单独的文件中会更常见。
    猜你喜欢
    • 2021-01-24
    • 1970-01-01
    • 2018-08-08
    • 2016-07-17
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    • 2016-10-24
    • 2016-06-18
    相关资源
    最近更新 更多