Emi
Emi

Reputation: 249

Spring: Environment specific configuration

Using Spring I need some kind of environment (dev|test|prod) specific properties.

I have exactly one configuration file (myapp.properties) and for some reasons I cannot have more than one configuration file (even spring can handle more than one).

So I need the possibility to add properties with a prefix like

dev.db.user=foo
prod.db.user=foo

and tell the application which prefix (environment) to use with a VM-argument like -Denv-target or something like this.

Upvotes: 3

Views: 8545

Answers (3)

t777
t777

Reputation: 3329

I use for this purpose a subcass of PropertyPlaceholderConfigurer:

public class EnvironmentPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

    private static final String ENVIRONMENT_NAME = "targetEnvironment";

    private String environment;

    public EnvironmentPropertyPlaceholderConfigurer() {
        super();
        String env = resolveSystemProperty(ENVIRONMENT_NAME);
        if (StringUtils.isNotEmpty(env)) {
            environment = env;
        }
    }

    @Override
    protected String resolvePlaceholder(String placeholder, Properties props) {
        if (environment != null) {
            String value = props.getProperty(String.format("%s.%s", environment, placeholder));
            if (value != null) {
                return value;
            }
        }
        return super.resolvePlaceholder(placeholder, props);
    }

}

and using it in applicationContext.xml (or any other spring-configuration file):

<bean id="propertyPlaceholder"class="EnvironmentPropertyPlaceholderConfigurer">
    <property name="location" value="classpath:my.properties" />
</bean>

In my.properties you can define properties like:

db.driverClassName=org.mariadb.jdbc.Driver
db.url=jdbc:mysql:///MyDB
db.username=user
db.password=secret
prod.db.username=prod-user
prod.db.password=verysecret
test.db.password=notsosecret

Thereby you can prefix properties keys by an environment key (e.g. prod).

Using the vm argument targetEnvironment you can choose the enviroment you like to use, e.g. -DtargetEnvironment=prod.

If no environment-specific-property exists, the default one (without a prefix) is choosen. (You should always define a default one.)

Upvotes: 5

yname
yname

Reputation: 2245

If you have environment variable and want to get property according this variable you can declare your properties that way:

<property name="username" value="${${env-target}.database.username}" />
<property name="password" value="${${env-target}.database.password}" />

Also make sure that you use properly configured property-placeholder:

<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>

Or, if you use special property configurer (e.g. EncryptablePropertyPlaceholderConfigurer), set properties:

<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />

But as mentioned earlier it is better to use profiles.

Upvotes: 2

sgroh
sgroh

Reputation: 354

I don't know what are your constraints to avoid having more than one configuration file but you can use something like -Denvtarget=someValue and in java do:

//Obtain the value set in the VM argument 
String envTarget= System.getProperty("env-target");

Properties properties;
try {
   properties = PropertiesLoaderUtils.loadAllProperties("myapp.properties");
} catch (IOException exception) {
  //log here that the property file does not exist.    
}

//use here the prefix set in the VM argument.
String dbUser = properties.getProperty(envTarget+".db.user");

Upvotes: 2

Related Questions