Loading environment specific configurations and properties with Spring using Maven Profiles and Settings Example
In this example we shall show you how to load specific environment configurations and properties with Spring using Maven POM Profiles and XML Settings. Our previous example, shows how to load specific environment configurations and properties using Spring where these properties files are located inside the project resource folder.
However, sometimes we have a sensitive authentication information like database user name, passwords, etc., and uploading such piece of information on version control system (Git, SVN) may not be allowed. So, using Maven settings.xml
file as an external properties values holder outside our project directory is a good approach where it will not be bundled with the project.
When Maven loads the project’s POM, it will pickup the given activated profile from the settings.xml
file, and inject the properties declared within the profile in the corresponding POM profile.
Now, It’s the time for Spring magic which supports using PropertySourcesPlaceholderConfigurer
configured with its environment-specific properties file. Now we can activate the desired environment Maven profile while we are building our application, that allows to load specific configurations beans and properties by deployment regions, such as “development”, “testing” and “production”, etc.
Let’s start our example below which shows how to use this feature where we have two environment-specific properties (Database
, JMS
) where each environment has different values for these properties. So, we need to load these properties at each environment.
1. Project Environment
- Spring 4.1.5
- Spring Test 4.1.5
- JUnit 4.12
- Apache Maven 3.0.5
- JDK 1.8
- Eclipse 4.4 (Luna)
2. Project Structure
We create a simple Spring Maven project with the following Structure.

3. Maven Profiles with Settings.xml
We have the following three Maven profiles (dev
, test
and prod
) inside our below POM file.
pom.xml:
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | < project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" < modelVersion >4.0.0</ modelVersion > < groupId >com.jcg.example</ groupId > < artifactId >springmavenproperties-example-code</ artifactId > < packaging >jar</ packaging > < version >1.0</ version > < name >Spring Maven Properties Example Code</ name > < properties > <!-- Generic properties --> < java.version >1.8</ java.version > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > < project.reporting.outputEncoding >UTF-8</ project.reporting.outputEncoding > < resource.directory >src/main/resources</ resource.directory > <!-- Spring --> < spring-framework.version >4.1.5.RELEASE</ spring-framework.version > <!-- Logging --> < log4j.version >1.2.17</ log4j.version > <!-- Test --> < junit.version >4.12</ junit.version > </ properties > < dependencies > <!-- Spring --> < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-context</ artifactId > < version >${spring-framework.version}</ version > </ dependency > <!-- Logging with Log4j --> < dependency > < groupId >log4j</ groupId > < artifactId >log4j</ artifactId > < version >${log4j.version}</ version > </ dependency > <!-- Test Artifacts --> < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-test</ artifactId > < version >${spring-framework.version}</ version > < scope >test</ scope > </ dependency > < dependency > < groupId >junit</ groupId > < artifactId >junit</ artifactId > < version >${junit.version}</ version > < scope >test</ scope > </ dependency > </ dependencies > < profiles > < profile > < id >dev</ id > <!-- Dev Env. Properties --> < properties > < profile.name >${profile.name}</ profile.name > <!-- Database Properties --> < db.driverClass >${db.driverClass}</ db.driverClass > < db.connectionURL >${db.connectionURL}</ db.connectionURL > < db.username >${db.username}</ db.username > < db.password >${db.password}</ db.password > <!-- JMS Properties --> < jms.factory.initial >${jms.factory.initial}</ jms.factory.initial > < jms.provider.url >${jms.provider.url}</ jms.provider.url > < jms.queue >${jms.queue}</ jms.queue > </ properties > </ profile > < profile > < id >test</ id > <!-- Test Env. Properties --> < properties > < profile.name >${profile.name}</ profile.name > <!-- Database Properties --> < db.driverClass >${db.driverClass}</ db.driverClass > < db.connectionURL >${db.connectionURL}</ db.connectionURL > < db.username >${db.username}</ db.username > < db.password >${db.password}</ db.password > <!-- JMS Properties --> < jms.factory.initial >${jms.factory.initial}</ jms.factory.initial > < jms.provider.url >${jms.provider.url}</ jms.provider.url > < jms.queue >${jms.queue}</ jms.queue > </ properties > </ profile > < profile > < id >prod</ id > <!-- Prod Env. Properties --> < properties > < profile.name >${profile.name}</ profile.name > <!-- Database Properties --> < db.driverClass >${db.driverClass}</ db.driverClass > < db.connectionURL >${db.connectionURL}</ db.connectionURL > < db.username >${db.username}</ db.username > < db.password >${db.password}</ db.password > <!-- JMS Properties --> < jms.factory.initial >${jms.factory.initial}</ jms.factory.initial > < jms.provider.url >${jms.provider.url}</ jms.provider.url > < jms.queue >${jms.queue}</ jms.queue > </ properties > </ profile > </ profiles > < build > < plugins > < plugin > < artifactId >maven-compiler-plugin</ artifactId > < version >3.2</ version > < configuration > < source >${java.version}</ source > < target >${java.version}</ target > </ configuration > </ plugin > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-resources-plugin</ artifactId > < version >2.6</ version > < configuration > <!-- specify UTF-8, ISO-8859-1 or any other file encoding --> < encoding >${project.build.sourceEncoding}</ encoding > </ configuration > </ plugin > </ plugins > < resources > <!-- Placeholders that are found from the files located in the configured resource directories are replaced with the property values found from the profile specific configuration file. --> < resource > < directory >${resource.directory}</ directory > < filtering >true</ filtering > </ resource > </ resources > </ build > </ project > |
Also, we have the below settings.xml
XML file, contains the previous POM profiles where each one contains the properties values.
Although, there are more than one elements which configure the core behavior of Maven like (servers
, mirrors
, proxies
, profiles
, activeProfiles
, etc.), We will focus on profiles
and activeProfiles
which serve our topic.
settings.xml:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 <!-- Active Profile Section --> < activeProfiles > < activeProfile >dev</ activeProfile > </ activeProfiles > < profiles > < profile > < id >dev</ id > <!-- Dev Env. Properties --> < properties > < profile.name >dev</ profile.name > <!-- Database Properties --> < db.driverClass >com.mysql.jdbc.Driver</ db.driverClass > < db.connectionURL >jdbc:mysql://localhost:3306/emp</ db.connectionURL > < db.username >dev_usr</ db.username > < db.password >dev_pss</ db.password > <!-- JMS Properties --> < jms.factory.initial > org.apache.activemq.jndi.ActiveMQInitialContextFactory </ jms.factory.initial > < jms.provider.url >tcp://localhost:61616</ jms.provider.url > < jms.queue >dev.queue</ jms.queue > </ properties > </ profile > < profile > < id >test</ id > <!-- Test Env. Properties --> < properties > < profile.name >test</ profile.name > <!-- Database Properties --> < db.driverClass >com.mysql.jdbc.Driver</ db.driverClass > < db.connectionURL >jdbc:mysql://192.168.1.2:3306/emp</ db.connectionURL > < db.username >test_usr</ db.username > < db.password >test_pss</ db.password > <!-- JMS Properties --> < jms.factory.initial > org.apache.activemq.jndi.ActiveMQInitialContextFactory </ jms.factory.initial > < jms.provider.url >tcp://192.168.1.2:61616</ jms.provider.url > < jms.queue >test.queue</ jms.queue > </ properties > </ profile > < profile > < id >prod</ id > <!-- Prod Env. Properties --> < properties > < profile.name >prod</ profile.name > <!-- Database Properties --> < db.driverClass >com.mysql.jdbc.Driver</ db.driverClass > < db.connectionURL >jdbc:mysql://192.168.1.1:3306/emp</ db.connectionURL > < db.username >prod_usr</ db.username > < db.password >prod_pss</ db.password > <!-- JMS Properties --> < jms.factory.initial > org.apache.activemq.jndi.ActiveMQInitialContextFactory </ jms.factory.initial > < jms.provider.url >tcp://192.168.1.1:61616</ jms.provider.url > < jms.queue >prod.queue</ jms.queue > </ properties > </ profile > </ profiles > </ settings > |
4. Properties File
We have the following properties file application.properties
where we need to load specific-environment values for each property in that file.
application.properties:
01 02 03 04 05 06 07 08 09 10 | # Database Properties db.driverClass=${db.driverClass} db.connectionURL=${db.connectionURL} db.username=${db.username} db.password=${db.password} # JMS Properties jms.factory.initial=${jms.factory.initial} jms.provider.url=${jms.provider.url} jms.queue=${jms.queue} |
5. ApplicationProperties Spring Component
We create ApplicationProperties.java
as a Spring component class annotated by @Component
which will be a singleton bean, we can autowire it to get properties using getProperty(String propName)
.
ApplicationProperties.java:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.jcg.prop; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.PropertySources; import org.springframework.core.env.Environment; /** * @author ashraf_sarhan * */ @Configuration @PropertySources ({ @PropertySource (value = "properties/application.properties" , ignoreResourceNotFound = true ) }) public class ApplicationProperties { @Autowired private Environment env; public String getProperty(String propName) { return env.getProperty(propName); } } |
- Register a Properties File via Java Annotations:
Spring 3.1 also introduces the new@PropertySource
annotation, as a convenient mechanism of adding property sources to the environment. This annotation is to be used in conjunction with Java based configuration and the@Configuration
annotation:12@Configuration
@PropertySources
({
@PropertySource
(value =
"properties/application.properties"
, ignoreResourceNotFound =
true
) })
- Using / Injecting Properties:
Unlike Our previous example where we are using@Value
for injecting a property, we will obtain the value of a property with the new Environment API:123456@Autowired
private
Environment env;
public
String getProperty(String propName) {
return
env.getProperty(propName);
}
- Properties Wrappers:
As you can notice that we have different properties type such Database, JMS, etc. So, for more organized properties management, we wrapped each type in a wrapper Spring components where all database properties were wrapped in theDatabaseProperties.java
and all JMS properties were wrapped in theJmsProperties.java
as well, that will lead to more clean and maintainable code where we can autowire them and getting any property value through its getter method and not by the property name. So, we can do any change in the property name in its wrapper class without breaking the code which consumes the changed property.As you notice that we have an
init()
annotated by@PostConstruct
, this method will be executed after dependency injection is done to initialize properties values after beans instantiation.DatabaseProperties.java:
01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061package
com.jcg.prop;
import
javax.annotation.PostConstruct;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.stereotype.Component;
/**
* @author ashraf_sarhan
*
*/
@Component
public
class
DatabaseProperties {
@Autowired
private
ApplicationProperties applicationProperties;
private
String driverClass;
private
String connectionURL;
private
String username;
private
String password;
@PostConstruct
private
void
init() {
this
.driverClass = applicationProperties
.getProperty(PropertiesConstants.DB_DRIVERCLASS);
this
.connectionURL = applicationProperties
.getProperty(PropertiesConstants.DB_CONNECTION_URL);
this
.username = applicationProperties
.getProperty(PropertiesConstants.DB_USERNAME);
this
.password = applicationProperties
.getProperty(PropertiesConstants.DB_PASSWORD);
}
public
String getDriverClass() {
return
driverClass;
}
public
String getConnectionURL() {
return
connectionURL;
}
public
String getUsername() {
return
username;
}
public
String getPassword() {
return
password;
}
@Override
public
String toString() {
return
"DatabaseProperties [driverClass="
+ driverClass
+
", connectionURL="
+ connectionURL +
", username="
+ username
+
", password="
+ password +
"]"
;
}
}
JmsProperties.java:
01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152package
com.jcg.prop;
import
javax.annotation.PostConstruct;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.stereotype.Component;
/**
* @author ashraf_sarhan
*
*/
@Component
public
class
JmsProperties {
@Autowired
private
ApplicationProperties applicationProperties;
private
String factoryInitial;
private
String providerUrl;
private
String queue;
@PostConstruct
private
void
init() {
this
.factoryInitial = applicationProperties
.getProperty(PropertiesConstants.JMS_FACTORY_INITIAL);
this
.providerUrl = applicationProperties
.getProperty(PropertiesConstants.JMS_PROVIDER_URL);
this
.queue = applicationProperties
.getProperty(PropertiesConstants.JMS_QUEUE);
}
public
String getFactoryInitial() {
return
factoryInitial;
}
public
String getProviderUrl() {
return
providerUrl;
}
public
String getQueue() {
return
queue;
}
@Override
public
String toString() {
return
"JmsProperties [factoryInitial="
+ factoryInitial
+
", providerUrl="
+ providerUrl +
", queue="
+ queue +
"]"
;
}
}
Also, we have a supplementary class PropertiesConstants.java
which contains properties keys constants which are used through the code.
PropertiesConstants.java:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | package com.jcg.prop; /** * @author ashraf_sarhan * */ public class PropertiesConstants { // Database Properties Constants public static final String DB_DRIVERCLASS = "db.driverClass" ; public static final String DB_CONNECTION_URL = "db.connectionURL" ; public static final String DB_USERNAME = "db.username" ; public static final String DB_PASSWORD = "db.password" ; // JMS Properties Constants public static final String JMS_FACTORY_INITIAL = "jms.factory.initial" ; public static final String JMS_PROVIDER_URL = "jms.provider.url" ; public static final String JMS_QUEUE = "jms.queue" ; } |
Finally, to allow the autowiring of our ApplicationProperties.java
Spring component, we created the following Spring context file.
app-context.xml:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | <? xml version = "1.0" encoding = "UTF-8" ?> 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"> <!-- scans for annotated classes in the com.company package --> < context:component-scan base-package = "com.jcg" /> <!-- enables annotation based configuration --> < context:annotation-config /> </ beans > |
6. ApplicationProperties Unit Test
Now, it’s the time for testing the previous code. Let’s run our JUnit test class ApplicationPropertiesTest.java
and see the output.
As you will see, we can running our unit test using two ways:
- Running the unit test while building the project with a specific profile by executing the following command line from inside the project directory where we can explicitly activate any profile through binding its id value using the -P CLI Maven option, This option takes an argument that is a comma-delimited list of profile-ids to use. When this option is specified, no profiles other than those specified in the option argument will be activated.1
mvn clean install -Pdev -s settings.xml
- This time, we will run the unit test while building the project with a specific profile but we will implicitly activate our desired profile via the
<activeProfiles>
section in Maven settings.xml file, This section takes a list of elements, each containing a profile-id inside.- Firstly, we will add the
<activeProfiles>
section in oursettings.xml
file.1234567<
settings
>
...
<
activeProfiles
>
<
activeProfile
>dev</
activeProfile
>
</
activeProfiles
>
...
</
settings
>
- Finally, we will execute the following command line from inside the project directory.1
mvn clean install -s settings.xml
- Firstly, we will add the
As you notice in both ways, We are binding
settings.xml
using the -s CLI Maven option, This option takes an argument that is a Maven settings absolute file path.ApplicationPropertiesTest.java:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | package com.jcg.test; import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.jcg.prop.DatabaseProperties; import com.jcg.prop.JmsProperties; /** * @author ashraf_sarhan * */ @RunWith (SpringJUnit4ClassRunner. class ) @ContextConfiguration ( "classpath:spring/app-context.xml" ) public class ApplicationPropertiesTest extends TestCase { @Autowired private DatabaseProperties databaseProperties; @Autowired private JmsProperties jmsProperties; @Test public void testApplicationProperties() { // Using application properties through properties wrappers System.out.println(databaseProperties.toString()); System.out.println(jmsProperties.toString()); } } |
Output:

7. Download the Source Code of this example
This was an example on how to load environment configurations and properties with Spring.
You can download the full source code of this example here: SpringMavenPropertiesExampleCode.zip
I get “Failed to load ApplicationContext” when running this code. How would I fix this?