One of the more common aspects of enterprise application development involves environment specific properties files. Some examples include Database configurations or external JMS resources etc. The common way to address this problem is to use multiple properties file an build the Application EAR/WAR/JAR at compile time. Although this works, this solution also means that we maintain different build scripts for different environments, or having some file renames etc. while building the application. Spring profiles address this problem in a more efficient way. Like any other property, using Spring profiles, we can inject the environment profile into Spring and Spring will handle the loading of the appropriate configuration files. In this post, I show how to load environment specific properties files using Spring.
This example shows a simple application that has three environments dev,qa, and prod. Each environment has it's own properties files and we expect to print the properties based on the environment property passed from command line. Here are the important steps
- Define profiles in Spring context file
<beans profile="dev">
<context:property-placeholder
location="classpath:config-default.properties, classpath:config-dev.properties"
ignore-unresolvable="true" />
</beans>
- Inject the environment variables using
${}
into the required classes.@Value("${app.name}")
private String appName;
- Pass the profile information from command line, or update environment in code.
gradle run -Dspring.profiles.active=prod
ConfigurableEnvironment env = (ConfigurableEnvironment) context.getEnvironment();
env.setActiveProfiles("qa");
((AbstractApplicationContext) context).refresh();
Here is the full code
Directory Structure
SpringEnvProperties
└───src
├───main
│ ├───java
│ │ └───com
│ │ └───aoj
│ │ │ SpringEnvProperties.java
│ │ │
│ │ └───service
│ │ DependsOnEnv.java
│ │
│ └───resources
│ applicationContext.xml
│ config-default.properties
│ config-dev.properties
│ config-prod.properties
│ config-qa.properties
│
└───test
└───java
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.aoj.service" />
<beans profile="dev">
<context:property-placeholder
location="classpath:config-default.properties, classpath:config-dev.properties"
ignore-unresolvable="true" />
</beans>
<beans profile="qa">
<context:property-placeholder
location="classpath:config-default.properties, classpath:config-qa.properties"
ignore-unresolvable="true" />
</beans>
<beans profile="prod">
<context:property-placeholder
location="classpath:config-default.properties, classpath:config-prod.properties"
ignore-unresolvable="true" />
</beans>
</beans>
config-default.properties
app.name=SpringEnvProperties
config-dev.properties
env.name=dev
env.prop1=propDev
config-qa.properties
env.name=qa
env.prop1=propQA
config-prod.properties
env.name=prod
env.prop1=propProduction
SpringEnvProperties.java
package com.aoj;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import com.aoj.service.DependsOnEnv;
public class SpringEnvProperties {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml");
System.out.println("Properties : " + System.getProperty("spring.profiles.active"));
DependsOnEnv test = context.getBean(DependsOnEnv.class);
test.printEnv();
// Update environment from code.
ConfigurableEnvironment env = (ConfigurableEnvironment) context.getEnvironment();
env.setActiveProfiles("qa");
((AbstractApplicationContext) context).refresh();
test = context.getBean(DependsOnEnv.class);
test.printEnv();
}
}
DependsOnEnv.java
package com.aoj.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class DependsOnEnv {
@Value("${app.name}")
private String appName;
@Value("${env.name}")
private String envName;
@Value("${env.prop1}")
private String envProp1;
public void printEnv() {
System.out.println("App Name : " + appName);
System.out.println("Current Env : " + envName);
System.out.println("Current Env Prop : " + envProp1);
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getEnvName() {
return envName;
}
public void setEnvName(String envName) {
this.envName = envName;
}
public String getEnvProp1() {
return envProp1;
}
public void setEnvProp1(String envProp1) {
this.envProp1 = envProp1;
}
}
build.gradle
apply plugin:'application'
mainClassName = "com.aoj.SpringEnvProperties"
applicationName = 'SpringEnvProperties'
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.springframework', name: 'spring-core', version: '4.3.9.RELEASE'
compile group: 'org.springframework', name: 'spring-context', version: '4.3.9.RELEASE'
compile group: 'org.springframework', name: 'spring-beans', version: '4.3.9.RELEASE'
compile group: 'org.springframework', name: 'spring-tx', version: '4.3.9.RELEASE'
compile group: 'org.springframework', name: 'spring-orm', version: '4.3.9.RELEASE'
// Use JUnit test framework
compile 'junit:junit:4.12'
}
// Required to pass gradle command-line system properties to the Java process
run {
systemProperty "spring.profiles.active", System.getProperty("spring.profiles.active")
}
Caution for Gradle users
While using gradle, if you do not pass the System properties using "systemProperty" as shown in the
build.gradle
file above, you will see that the properties will not be passed to the java program, and you might see something like below
INFO: Skipped XML bean definition file due to specified profiles [prod] not matching: class path resource [applicationContext.xml]
Properties : null
App Name : ${app.name}
Current Env : ${env.name}
Current Env Prop : ${env.prop1}
You can see that instead of the environment properties, it will just print the
${}
.
No comments:
Post a Comment