简体   繁体   中英

Dynamically load files on classpath using ReloadableResourceBundleMessageSource

I'm new to Spring and am attempting to use it's ReloadableResourceBundleMessageSource class.

I'm attempting to use it so that we no longer have to restart our web app for properties files changes/updates.

I have a web app (Primarily using JSF) and a separate tar component which contains all my properties files.

The structure of the properties tar is as follows:

 - CompanyOneMessages.properties
 - CompanyOneMessages_fr_FR.properties
 - CompanyTwoMessages.properties
 - CompanyTwoMessages_fr_FR.properties
 - CompanyThreeMessages.properties
 - CompanyThreeMessages_fr_FR.properties
 - ...

This tar is unzipped and deployed to a location on the server which is specified as been on the classpath within the websphere configurations.

I added the following to my applicationContext-config.xml:

<!-- Enable reloading of resource bundles without requiring web-app restart -->
    <bean id="messages"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames">
            <list>  
                <value>classpath:com/resource/dynamic/CompanyOneMessages</value>
                <value>classpath:com/resource/dynamic/CompanyTwoMessages</value>
                <value>classpath:com/resource/dynamic/CompanyThreeMessages</value>              
            </list>
        </property>     
        <property name="cacheSeconds" value="1" />
    </bean>

    <!-- Declare location of bean to handle messages and define property reference 
         we will use to reference message properties throughout the presentation layer -->
    <bean id="myappMessages" class="com.myapp.resource.MyAPPMessages">
        <property name="messages" ref="messages" />
    </bean>

This all works fine.

BUT, it does not fully fix the original problem. Any time I want to add a new company to our application, I will have to add a new line to the applicationContext-config.xml file and redeploy/restart the web app.

I would like to be able to simply drop the new company properties file into the properties tar and for it to be dynamically picked up.

Is it possible to extend the ReloadableResourceBundleMessageSource class in such a way that it will search the class-path for properties files on application start-up and dynamically load all of them?

Update

This is what I have so far:

applicationContext-config.xml:

<bean id="messages" class="com.resource.MyAPPReloadableResourceBundleMessageSource">
</bean>

MyAPPReloadableResourceBundleMessageSource:

package com.myapp.resource;

import org.springframework.context.support.ReloadableResourceBundleMessageSource;

public class MyAPPReloadableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource
{   
    public MyAPPReloadableResourceBundleMessageSource()
    {   
        getResourceBundlesMessages();

        // Simply single basename test
        setBasename("classpath:/resource/dynamic/companyOneMessages");      
    }

    @Override
    public void setBasename(String baesname)
    {
        System.out.println("In setBasename");
        super.setBasename(baesname);
    }

    @Override
    public void setBasenames(String[] baesnames)
    {
        System.out.println("In setBasenames");
        super.setBasenames(baesnames);
    }

    private String[] getResourceBundlesMessages()
    {
        String[] propertiesFiles = null;

        // How do I get all filenames with .properties under com.resources.dynamic? (location is under classpath)

        return propertiesFiles;
    }
}

So all I need is how to get a list of all files under the classpath with .properties extension?

Thanks

Thomas

ReloadableResourceBundleMessageSource要求文件位于webapp /目录下,而不是在类路径中(它不能重新加载)。

You are on the right path of extending ReloadableResourceBundleMessageSource . As @JamesC mentioned, and per Spring's API documentation 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).

I had a similar requirement as you. The key to solving it is extending ReloadableResourceBundleMessageSource and overriding the calculateAllFilenames(String basename, Locale locale) method to do more than appending language codes to the basename.

For example, if I have all my external message properties files under /srv/myapp/messages (in the filesystem, NOT classpath), the overridden method would do something like:

@Override
protected List<String> calculateAllFilenames(final String basename,
        final Locale locale) {

   return super.calculateAllFilenames("file:///srv/myapp/messages/" + basename, 
           locale);
}

In my case, my list of basenames are static and thus, I did not have to override other methods that calls calculateAllFilenames() for each base name.

In your specific case, I would use Company as the base name and override calculateAllFilenames() to scan a directory outside of your classpath to resolve actual basenames and then call super.calculateAllFilenames() for each resolved basename (ie super.calculateAllFilenames("file:///path/to/CompanyOneMessages", locale) ). Potentially, something similar to https://stackoverflow.com/a/11223178/1034436 would help. Note: unlike the referenced answer, I would not do the directory scan as part of a property setter if the resolved list of base names can change dynamically. Of course, performance considerations for your app will also need to be weighed in as it would obviously drastically increase filesystem access.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM