ptomli
ptomli

Reputation: 11818

Configuring Spring based servlet with sysadmin defined properties

I have a web application that's based on Spring and the application contexts, applicationContext.xml and myServlet-servlet.xml contain settings that should be configurable by the sysadmin in deployment.

What's the best way to enable changing of settings like [database server details, remote webservice endpoints, etc] without requiring editing of the WAR contents?

Spring provides the PropertyPlaceholderConfigurer which can be used in the beans configurations, but I think that's going to require an absolute path to the properties file, which I'd like to avoid, if for no other reason than to allow multiple instances of the same servlet to run on the same machine.

There's also maybe the option to use JNDI configured resources, though there doesn't appear to be a BeanFactoryPostProcessor implementation out-the-box doing this so it might not be a good way to approach it.

What's the standard best-practice, if there is one, to deal with this sort of requirement?

Related SO entries:

How can I specify system properties in Tomcat configuration on startup?

Upvotes: 1

Views: 1247

Answers (3)

sourcerebels
sourcerebels

Reputation: 5180

If you don't want to externalize your properties file:

I'm using a prefix that represents my deployment environment in my properties. Example:

#Test url
test.url=http://test.url.com

#Production URL
prod.url=http://prod.url.com

I defined a system property named "entorn" in each environment (-D argument to jvm call in your application server start script). The value of this property is "test" in my test environment and "prod" in my production environment.

Then I defined my "propertyConfigurer" bean:

<bean id="propertyConfigurer" class="es.indra.ccma.config.EnvironmentPropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:ccma.properties</value>
        </list>
    </property>
</bean>

The EnvironmentPropertyPlaceholderConfigurer code:

package es.indra.ccma.config;

import java.util.Properties;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

public class EnvironmentPropertyPlaceholderConfigurer extends
        PropertyPlaceholderConfigurer {

    private String environment;
    final private static String ENV_SYSTEM_PROPERTY = "entorn";

    public EnvironmentPropertyPlaceholderConfigurer() {

        environment = System.getProperty(ENV_SYSTEM_PROPERTY);
        if (environment == null) {
            //default environment
            environment = "test";
        }
    }
    protected String resolvePlaceholder(String placeholder, Properties props) {

        final String envPlaceholder = environment + "." + placeholder;
        if (props.containsKey(envPlaceholder)) {
            return props.getProperty(envPlaceholder);
        } else {
            return props.getProperty(placeholder);
        }
    } 
}

If you are running your code in "test" environment and you want to retrieve the value of "url" property, the propertyConfigurer looks for "test.url" in your properties files and if no "test.url" property found it will look for "url" property.

This is not my idea I followed this tutorial to acomplish this.

Upvotes: 0

Pablojim
Pablojim

Reputation: 8582

You can also achieve this with a file based solution. On each environment define a environment name system property. Then use this name to load an external properties file. The example below loads a default set that is then overrided with a environment specific set.

<bean id="propertyPlaceholderConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="locations">
            <list>
                    <value>classpath:site/properties/default/placeholder.properties
                    </value>
                    <value>file:///site/properties/${env.name}/placeholder.properties
                    </value>
            </list>
    </property>
</bean>

Adapted from, my answer here

Upvotes: 1

duffymo
duffymo

Reputation: 308743

"What's the best way to enable changing of settings like [database server details, remote webservice endpoints, etc] without requiring editing of the WAR contents?"

The only way to do that is to externalize the configuration. You can explode the WAR file, move the .properties file outside the WAR (as long as it's in the CLASSPATH, Spring will find it), or put the modifiable values in a database.

Upvotes: 1

Related Questions