Java 如何使用注释在 Spring 4 中重新加载属性文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26150527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 01:54:36  来源:igfitidea点击:

How can I reload properties file in Spring 4 using annotations?

javaspringpropertiesannotations

提问by J?rgen Sk?r Fischer

I have a simple application where i am using several properties-files to fetch content edited by other users (links to sites etc).

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

The class where i load the properties look like this:

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

@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();
   }
}

Some of the properties file:

一些属性文件:

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

This works fine, but if i make changes to the properties-file, i have to reload the app to visualise any changes made.

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

Is it possible, if i move the location to disk instead of classpath, to reload this periodically or manually? I do not want this to be done automatically on change, as i want to have control over when this is done / updated.

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

回答by Mikus111

This works a treat. Requires Java 7, Apache commons logging, Apache commons lang (v2.6) and Apache commons Configuration:

这是一种享受。需要 Java 7、Apache commons logging、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);
    }
}

and test it with:

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

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"));
        }
    }
}

Output when you change test.properties is something like this (original contents of test.props was key=value, later changed to key=value1 mid-program execution):

更改 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

You could also consider Official Spring Framework Reference DocumentationRefreshable beans, using a DSLlike Groovy for this.

您还可以考虑官方 Spring 框架参考文档Refreshable beans,为此使用像 Groovy 这样的DSL

回答by Nonlone

the PropertyPlaceholderConfigurer need to be override to reload the new Properties

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

You need to rewrite processPropertiesmethod to make the StringValueResolverwhich contains the properties became to loadable. This is my code

您需要重写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;
        }
   }
}

here is the configure for properties-config.xml.all of those properties can be reload in runtime as a prototype bean.

这是配置。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>`

回答by Mohit Singh

Inside applicationContext.xml

在 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>