Pergunta

I was hoping for a little help with a problem I am having involving properties files in Spring. So the setup I have is like so:

opto-mapping.properties – this is located in my src folder and contains translations for my optimised resources like so:

generic-min.css=4037119659.css

This properies file is updated every time the build ‘optimise’ is run. I then use

<fmt:setBundle basename="opto-mapping" />

To import my properties file in my desired jsp. Then referencing the content by using:

<fmt:message key='generic-min.css' />

This all works beautifully except that the properties file requires a tomcat restart to be reloaded. I dont want to have to start taking sites down everytime a resource is updated. I would like the properties file to automatically reload every so often.

I did attempt to update an existing bean in my spring-context.xml to reload this properties file like I do with translations but this has not worked - more than likely because of the opto-mapping.properties files location - but you see it needs to be in that location to load using fmt:setBundle.

<bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="cacheSeconds">
            <value>1</value>
        </property>
        <property name="basenames">
            <list>
                <value>WEB-INF/translations/translations</value>
                <value>WEB-INF/classes/opto-mapping</value>
            </list>
        </property>
</bean>

Any help or a point in the right direction would be greatly appreciated in this difficult time.

I hope all this makes senese and many thanks in advance!

G.

Foi útil?

Solução

There are a few things you might try.

<fmt:setBundle> will eventually call ResourceBundle.getBundle(String, Locale, ClassLoader), where the string will be your basename and the classloader will be Thread.currentThread().getContextClassLoader(). If you're using JDK 1.6, you can try using ResourceBundle.clearCache(ClassLoader) to clear the bundle cache. It would make sense to do this in a servlet filter and combine it with some other logic to determine when the cache should be cleared.

Another angle is take more direct control over the loading of the properties file and the configuration of JSTL. Again, making use of a filter (ignoring exception handling):

ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
URL propsURL = ctxLoader.getResource("opto-mapping.properties");
URLConnection propsConn = propsURL.openConnection();
long propsLastModified = propsConn.getLastModified();
// decide if you want to reload...
propsConn.setUseCaches(false);
InputStream propsIn = propsConn.getInputStream();
ResourceBundle propsBundle = new PropertyResourceBundle(propsIn);
propsIn.close();
LocalizationContext propsCtx = new LocalizationContext(propsBundle);
ServletContext servletCtx = this.filterConfig.getServletContext();
Config.set(servletCtx, Config.FMT_LOCALIZATION_CONTEXT, propsCtx);

Then you can just use <fmt:message> in your pages. You can find the docs for LocalizationContext and Config in the JSTL API.

Lots of other variations are possible, but make sure to take a look at the newer ResourceBundle (including ResourceBundle.Control) additions to JDK 1.6, keep in mind the functionality of "lower-level" APIs like URLConnection, and become familiar with the more programmatic aspects of JSTL available through its API.

Outras dicas

Thank you both for your responses. I have now got this working and thought I would share the wealth.

So, I moved my properties file out of the src folder and into WEB-INF/properties.

I updated the following bean to load up the properties files:

<bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="cacheSeconds">
            <value>1</value>
        </property>
        <property name="basenames">
            <list>
                <value>WEB-INF/translations/translations</value>
                <value>WEB-INF/properties/opto-mapping</value>
            </list>
        </property>
    </bean>

Now, previously I was using setBundle to load into my properties file like this:

<fmt:setBundle basename="opto-mapping" />

But I found that obviously my properties file wasnt being loaded anymore because I had moved it. But because of my bean setup the new properties file was being loaded but my setBundle was overwritting that.

So, the solution was to remove the setBundle and now my properties file is reloading!

Thanks again!

Tomcat will not reload resources that are on the classpath. This is stated in the javadoc for ReloadableResourceBundleMessageSource:

Since application servers typically cache all files loaded from the classpath, it is necessary to store resources somewhere else (for example, in the "WEB-INF" directory of a web app). Otherwise changes of files in the classpath will not be reflected in the application.

Such classpath locations include WEB-INF/classes, and will not be released.

Try moving opto-mapping.properties elsewhere (e.g. WEB-INF/messages), and try it then.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top