在设置 属性 占位符之前使用 System属性Initializer 设置 System属性

Use of SystemPropertyInitializer to set System Property before setting property placeholder

根据 this answer,您可以使用 Spring 批处理 class org.springframework.batch.support.SystemPropertyInitializer 在 [=30= 启动期间设置系统 属性 ] 上下文。

特别是,我希望能够使用它来设置 ENVIRONMENT 因为 Spring 批处理配置的一部分读取:

<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:/org/springframework/batch/admin/bootstrap/batch.properties</value>
            <value>classpath:batch-default.properties</value>
            <value>classpath:batch-${ENVIRONMENT:hsql}.properties</value>
        </list>
    </property>
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="ignoreResourceNotFound" value="true" />
    <property name="ignoreUnresolvablePlaceholders" value="false" />
    <property name="order" value="1" />
</bean>

但是 SystemPropertyInitializer 使用 afterPropertiesSet() 来设置系统 属性,显然这会发生 配置 PropertyPlaceholderConfigurer 之后.

有可能实现吗?

最简单的解决方案是将环境 属性 作为命令行参数传入,因此它可以作为系统 属性.

解析

如果这不是一个选项,您可以实施 ApplicationContextInitializer 将环境属性提升为系统属性。

public class EnvironmentPropertyInitializer implements 
                   ApplicationContextInitializer<ConfigurableApplicationContext> {

    boolean override = false; //change if you prefer envionment over command line args

    @Override
    public void initialize(final ConfigurableApplicationContext applicationContext) {
        for (Entry<String, String> environmentProp : System.getenv().entrySet()) {
            String key = environmentProp.getKey();
            if (override || System.getProperty(key) == null) {
                System.setProperty(key, environmentProp.getValue());
            }
        }
    }
}

这里看起来您正在使用 Spring Batch Admin,因此您可以通过在 web.xml 文件中添加一些内容来注册您的初始化程序:

<context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>org.your.package.EnvironmentPropertyInitializer</param-value>
</context-param>

添加背景,因为评论似乎不够:这是相关的 类 以及它们的顺序 called/evaluated。

  1. ApplicationContextInitializer 告诉 Spring 应用程序如何加载应用程序上下文并可用于设置 bean 配置文件,以及更改上下文的其他方面。这会在 上下文完全创建之前 执行。
  2. PropertyPlaceholderConfigurerBeanFactoryPostProcessor 并调用 postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)。当设置由 BeanFactory.
  3. 创建的 bean 的属性时,这会修改 BeanFactory 以允许解析 ${my.property:some.default} 等属性
  4. SystemPropertyInitializer 实现 InitializingBean 并调用 afterPropertiesSet()。此方法在 bean 实例化并设置属性后运行。

所以你是对的,SystemPropertyInitializer 在这里没有帮助,因为它在 PropertyPlaceholderConfigurer 上设置属性后计算。但是,ApplicationContextInitializer 将能够将这些环境属性提升为系统属性,以便 XML.

可以解释它们

还有一点我忘了提,第一个声明的 bean 需要是:

 <context:property-placeholder/>

虽然它看起来多余,但它将允许您的 PropertyPlaceholderConfigurer bean 通过使用您刚刚提升的环境属性正确评估 ${ENVIRONMENT:hsql}