Dynamically loading properties file using Spring

46,720

Solution 1

You can use Spring's ReloadableResourceBundleMessageSource class like below:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <bean id="myProperties" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!-- check property file(s) every 1 second -->
        <property name="cacheSeconds" value="1"/>
        <property name="basenames">
            <list>
                <value>myApp/myApp</value>
            </list>
        </property>
    </bean>

</beans>

And then you can call MessageSource.getMessage() method to get the property value. Here is an example:

package com.example;

import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyApp {
public static void main(String[] args) throws InterruptedException {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("myApp/MyApp.xml");
        MessageSource myProperties = (MessageSource) ctx.getBean("myProperties");
        while (true) {
            System.out.println(myProperties.getMessage("myApp.propertyOne", null, null));
            Thread.sleep(1000);
        }
    }
} 

You can directly call ApplicationContext.getMessage(String code, Object[] args, Locale locale) if you renamed your 'myProperties' bean as 'messageSource'.

For your web apps, please put your property files outside of your web app's classpath (because the web server might cache them). For instance, WEB-INF/conf/myApp.properties

Solution 2

The following supports what you are looking for:

https://commons.apache.org/proper/commons-configuration/userguide/howto_properties.html

PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties");
config.setReloadingStrategy(new FileChangedReloadingStrategy());

This should do the trick. I haven't used it myself but it seems to be pretty straightforward.

Share:
46,720
RaceBase
Author by

RaceBase

#SOreadytohelp

Updated on May 10, 2020

Comments

  • RaceBase
    RaceBase almost 4 years

    I have written a PropertyUtils class (from internet), which will load the Properties

    <bean id="propertiesUtil" class="com.myApp.PropertiesUtil" >
        <property name="locations">
            <list>
                <value>classpath:myApp/myApp.properties</value>         
            </list>
        </property>
    </bean>
    

    and a PropertiesUtil class is like below

    public class PropertiesUtil extends PropertyPlaceholderConfigurer {
    
        private static Map<String, String> properties = new HashMap<String, String>();
    
        @Override
        protected void loadProperties(final Properties props) throws IOException {
            super.loadProperties(props);
            for (final Object key : props.keySet()) {
                properties.put((String) key, props.getProperty((String) key));
            }
        }
    
        public String getProperty(final String name) {
            return properties.get(name);
        }
    
    }
    

    Later, I can get the property by calling PropertiesUtil.getProperty() method.

    But now I want to modify it slightly such that, If the myApp.properties get modified/changed by user, it should be loaded again

    Probably I need FileWatcher class

    public abstract class FileWatcher extends TimerTask {
        private long timeStamp;
        private File file;
    
        public FileWatcher(File file) {
            this.file = file;
            this.timeStamp = file.lastModified();
        }
    
        @Override
        public final void run() {
            long timeStampNew = this.file.lastModified();
    
            if (this.timeStamp != timeStampNew) {
                this.timeStamp = timeStampNew;
                onChange(this.file);
            }
        }
    
        protected abstract void onChange(File newFile);
    }
    

    but my doubts are

    1. How do I create File object using classpath:myApp/myApp.properties (because absolute path is not known)
    2. How do I invoke/call spring to load/pass the new myApp.properties to PropetisUtil class [in onChange method].