【问题标题】:Use of SystemPropertyInitializer to set System Property before setting property placeholder在设置属性占位符之前使用 SystemPropertyInitializer 设置系统属性
【发布时间】:2017-08-12 13:51:37
【问题描述】:

根据this answer,您可以在Spring Context启动期间使用Spring Batch类org.springframework.batch.support.SystemPropertyInitializer设置系统属性。

特别是,我希望能够使用它来设置 ENVIRONMENT,因为 Spring Batch 配置的一部分内容如下:

<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 的配置之后发生的

有可能实现吗?

【问题讨论】:

    标签: java spring-batch spring-batch-admin system-properties property-placeholder


    【解决方案1】:

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

    如果这不是一个选项,您可以实现一个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>
    

    添加背景,因为评论似乎不够:以下是相关类以及它们被调用/评估的顺序。

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

    所以你说得对,SystemPropertyInitializer 在这里没有帮助,因为它在PropertyPlaceholderConfigurer 上设置属性后进行评估。但是,ApplicationContextInitializer 将能够将这些环境属性提升为系统属性,以便它们可以被 XML 解释。

    还有一点我忘了提到,第一个声明的 bean 必须是:

     <context:property-placeholder/>
    

    虽然这看起来是多余的,但它可以让您的 PropertyPlaceholderConfigurer bean 使用您刚刚提升的环境属性正确评估 ${ENVIRONMENT:hsql}

    【讨论】:

    • 我不确定系统属性和环境属性之间的差异有多适用。 SystemPropertyInitializer 类在其代码中调用 System.setProperty()。我遇到的是直到 placeholderProperties 被解决之前它不会被调用。这个解决方案不会遇到同样的问题吗?我对自己的 Spring 生命周期知识不够自信。
    • 在上面添加了详细信息(评论太长)
    猜你喜欢
    • 2012-06-05
    • 2018-06-15
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 2015-09-16
    • 2023-03-28
    • 1970-01-01
    • 2012-12-20
    相关资源
    最近更新 更多