【问题标题】:How can I reload properties file in Spring 4 using annotations?如何使用注释在 Spring 4 中重新加载属性文件?
【发布时间】:2014-11-26 20:01:36
【问题描述】:

我有一个简单的应用程序,我在其中使用多个属性文件来获取其他用户编辑的内容(网站链接等)。

我加载属性的类如下所示:

@Configuration
@PropertySource("classpath:salestipsWhitelist.properties")
public class SalestipsWhitelist {

@Autowired
Environment env;

public Environment getEnv() {
    return env;
}

public void setEnv(Environment env) {
    this.env = env;
}

@Bean
   public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
      return new PropertySourcesPlaceholderConfigurer();
   }
}

一些属性文件:

UPS_MPP_M_L=True
UPS_MPP_M_M=True
UPS_MPP_M_MP=True
UPS_MPP_M_S=True

这很好用,但如果我对属性文件进行更改,我必须重新加载应用程序以可视化所做的任何更改。

如果我将位置移动到磁盘而不是类路径,是否可以定期或手动重新加载?我不希望这在更改时自动完成,因为我想控制何时完成/更新。

【问题讨论】:

    标签: java spring properties annotations


    【解决方案1】:

    在 applicationContext.xml 中

    <bean id="beanId" class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy">
        <property name="refreshDelay" value="30000" /> <!-- 30 seconds -->
    </bean>
    <bean id="reloadableProperties" class="org.apache.commons.configuration.PropertiesConfiguration">
        <constructor-arg value="file:/web/${weblogic.Domain}/${weblogic.Name}/${app.Name}/reloadable_cfg/Reloadable.properties"/>
        <property name="reloadingStrategy" ref="propertiesReloadingStrategy"/>
    </bean>
    

    【讨论】:

    • 我们如何将这些属性反映到预定义的 bean?
    【解决方案2】:

    需要重写 PropertyPlaceholderConfigurer 以重新加载新的属性

    您需要重写processProperties 方法以使包含属性的StringValueResolver 变为可加载。 这是我的代码

    import java.io.IOException;
    import java.util.Properties;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
    import org.springframework.util.PropertyPlaceholderHelper;
    import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
    import org.springframework.util.StringValueResolver;
    
    
    public class ReloadablePropertyPlaceholderConfigurer 
                                        extends PropertyPlaceholderConfigurer {
    
        private ReloadablePlaceholderResolvingStringValueResolver reloadableValueResolver;
    
    
        public void reloadProperties() throws IOException {
            Properties props = mergeProperties();
            this.reloadableValueResolver.refreshProperties(props);
        }
    
    
        @Override
        protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
                throws BeansException {
            this.reloadableValueResolver = new ReloadablePlaceholderResolvingStringValueResolver(props);
            StringValueResolver valueResolver = this.reloadableValueResolver;
            this.doProcessProperties(beanFactoryToProcess, valueResolver);
        }
    
    
        private class ReloadablePlaceholderResolvingStringValueResolver 
                implements StringValueResolver {
    
            private final PropertyPlaceholderHelper helper;
            private final ReloadablePropertyPlaceholderConfigurerResolver resolver;
    
            public ReloadablePlaceholderResolvingStringValueResolver(Properties props) {
                this.helper = new PropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);
                this.resolver = new ReloadablePropertyPlaceholderConfigurerResolver(props);
            }
    
            @Override
            public String resolveStringValue(String strVal) throws BeansException {
                String value = this.helper.replacePlaceholders(strVal, this.resolver);
                return (value.equals(nullValue) ? null : value);
            }
    
            private void refreshProperties(Properties props){
                this.resolver.setProps(props);
            }
        }
    
        private class ReloadablePropertyPlaceholderConfigurerResolver 
                implements PlaceholderResolver {
    
            private Properties props;
            private ReloadablePropertyPlaceholderConfigurerResolver(Properties props) {
                this.props = props;
            }
    
            @Override
            public String resolvePlaceholder(String placeholderName) {
                return ReloadablePropertyPlaceholderConfigurer.this.resolvePlaceholder(placeholderName, props, SYSTEM_PROPERTIES_MODE_FALLBACK);
            }
    
            public void setProps(Properties props) {
                this.props = props;
            }
       }
    }
    

    这里是 properties-config.xml 的配置。所有这些属性都可以在运行时作为原型 bean 重新加载。

    <bean id="propertyConfigurer" class="com.cn21.mail189.analysis.commons.expand.ReloadablePropertyPlaceholderConfigurer">
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="locations">
            <list>
                <!-- database config -->
                <value>classpath:spring/dbconfig.properties</value>
                <!-- app config -->
                <value>classpath:spring/app.properties</value>
                <!-- some other config -->
                <value>classpath:xxxx.properties</value>
            </list>
        </property>
    </bean>`
    

    【讨论】:

    • 欢迎来到 SO。如果您可以添加代码来显示答案,这会有所帮助。
    • processProperties 中,我们将StringValueResolver 传递给doProcessProperties,后者将存储到beanfactory 中。 PlaceholderConfigurerSupport 类中的默认PlaceholderResolvingStringValueResolver 持有PropertyPlaceholderConfigurerResolver,当将其放在getContext 方法中时,将其保留在最终属性中,我们需要重写它
    • 我们如何在预定义的 bean 中反映这些属性变化?
    【解决方案3】:

    这是一种享受。需要 Java 7、Apache commons 日志记录、Apache commons lang (v2.6) 和 Apache commons 配置:

    package corejava.reloadTest;
    
    import org.apache.commons.configuration.ConfigurationException;
    import org.apache.commons.configuration.PropertiesConfiguration;
    import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
    
    public class MyApplicationProperties {
        private static PropertiesConfiguration configuration = null;
    
        static {
            try {
                configuration = new PropertiesConfiguration("test.properties");
            } catch (ConfigurationException e) {
                e.printStackTrace();
            }
            configuration.setReloadingStrategy(new FileChangedReloadingStrategy());
        }
    
        public static synchronized String getProperty(final String key) {
            return (String) configuration.getProperty(key);
        }
    }
    

    并使用以下方法对其进行测试:

    package corejava.reloadTest;
    
    public class TestReloading {
        public static void main(String[] args) {
            while (true) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(MyApplicationProperties.getProperty("key"));
            }
        }
    }
    

    更改 test.properties 时的输出是这样的(test.props 的原始内容是 key=value,后来在程序执行过程中更改为 key=value1):

    value
    value
    value
    value
    value
    Jan 17, 2015 2:05:26 PM org.apache.commons.configuration.PropertiesConfiguration reload
    INFO: Reloading configuration. URL is file:/D:/tools/workspace   /AutoReloadConfigUsingApacheCommons/resources/test.properties
    value1
    value1
    value1
    

    您也可以考虑 Official Spring Framework Reference Documentation Refreshable beans ,为此使用像 Groovy 这样的 DSL

    【讨论】:

    • 如果 jar 文件中有属性怎么办?
    • 不应该,否则每次您想更改配置值时都必须重新部署
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-09
    • 2012-10-26
    • 1970-01-01
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多