Profiles
Spring profiles provide a mechanism in the core container that allows for registration of different beans in different environments. In this article, we will go through the profile algorithm and the different ways of using it.
The profile attribute is part of beans element. If the beans element doesn’t have a profile attribute, then it will always be loaded irrespective of the active profiles set.
If it has a profile, then the active profiles must have at least one of those profile else the beans will not be loaded.
There can be multiple active profiles and multiple profiles in profile
attribute. The profiles need to be either delimited by space or comma delimited or semi-colon like profile="dev"
or profile="dev test"
or profile="dev, test"
or profile="dev; test"
.
![]() |
Spring Profiles |
No profiles attribute
What happens if active profiles are set but the context doesn’t have profiles attribute? Lets checks it out using an example.
My context file is testNoProfileAttribute.xml:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <bean id="foo" class="springdemo.Foo"/> </beans>
Active profile is set to dev
. There is no profile attribute but we should still be able to get the bean.
public void testContextWithNoProfileAttribute() { GenericXmlApplicationContext context = new GenericXmlApplicationContext(); context.getEnvironment().setActiveProfiles("dev"); context.load("springdemo/testNoProfileAttribute.xml"); context.refresh(); assertTrue(context.containsBean("foo")); }
Profile attribute specified in nested beans element
Now we look into another example where profiles
attribute is set in the nested beans
element.
In the below context file, bar
has two flavors of implementation depending on the profile.
Here is the context file: testProfile.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <bean id="foo" class="springdemo.Foo"> <property name="bar" ref="bar"/> </bean> <beans profile="prod"> <bean id="bar" class="springdemo.ProdBar"/> </beans> <beans profile="dev"> <bean id="bar" class="springdemo.DevBar"/> </beans> </beans>
We set the active profiles programatically. If active profile is dev
, we get DevBar
. If active profile is set to prod
, we can ProdBar
.
public void testProfileUsingBeansSubElement() { GenericXmlApplicationContext context = new GenericXmlApplicationContext(); context.getEnvironment().setActiveProfiles("dev"); context.load("springdemo/testProfile.xml"); context.refresh(); assertTrue(context.containsBean("foo")); Foo foo = (Foo) context.getBean("foo"); assertTrue(foo.getBar() instanceof DevBar); context = new GenericXmlApplicationContext(); context.getEnvironment().setActiveProfiles("prod"); context.load("springdemo/testProfile.xml"); context.refresh(); assertTrue(context.containsBean("foo")); foo = (Foo) context.getBean("foo"); assertTrue(foo.getBar() instanceof ProdBar); // We can also use ClassPathXmlApplicationContext ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(); appContext.getEnvironment().setActiveProfiles("dev"); appContext.setConfigLocation("springdemo/testProfile.xml"); appContext.refresh(); assertTrue(appContext.containsBean("foo")); foo = (Foo) appContext.getBean("foo"); assertTrue(foo.getBar() instanceof DevBar); }
No active profiles set
What happens if the context file is meant for a certain profile but not active profile is set?
Below example shows if the active profile is set, then it will result in bean creation failure while trying to create bean definition for “bar”.
public void testContextWithNoActiveProfiles() { try { GenericXmlApplicationContext context = new GenericXmlApplicationContext(); context.load("springdemo/testProfile.xml"); context.refresh(); } catch (BeanCreationException e) { } }
Profile context decoupled
In the below example, we decouple the profile based implementations from the common context and move into separate context files.
The common classes go here:
testProfileCommon.xml:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <bean id="foo" class="springdemo.Foo"> <property name="bar" ref="bar"/> </bean> </beans>
Dev based classes go here:
testDevProfile.xml:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <beans profile="dev"> <bean id="bar" class="springdemo.DevBar"/> </beans> </beans>
Prod based classes go here:
testProdProfile.xml:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <beans profile="prod"> <bean id="bar" class="springdemo.ProdBar"/> </beans> </beans>
The active profiles can be set either programatically or using a system property.
We will look into both the cases in the below test case.
Using setter method
public void testProfileUsingSetter() { GenericXmlApplicationContext context = new GenericXmlApplicationContext(); context.getEnvironment().setActiveProfiles("dev"); context.load("springdemo/testProfileCommon.xml", "springdemo/testDevProfile.xml", "springdemo/testProdProfile.xml"); context.refresh(); assertTrue(context.containsBean("foo")); Foo foo = (Foo) context.getBean("foo"); assertTrue(foo.getBar() instanceof DevBar); context = new GenericXmlApplicationContext(); context.getEnvironment().setActiveProfiles("prod"); context.load("springdemo/testProfileCommon.xml", "springdemo/testDevProfile.xml", "springdemo/testProdProfile.xml"); context.refresh(); assertTrue(context.containsBean("foo")); foo = (Foo) context.getBean("foo"); assertTrue(foo.getBar() instanceof ProdBar); }
Using system property
Profiles can be set externally using system property spring.profiles.active
public void testProfileUsingSystemProperty() { System.setProperty("spring.profiles.active", "dev"); ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("springdemo/testProfileCommon.xml", "springdemo/testDevProfile.xml", "springdemo/testProdProfile.xml"); Foo foo = (Foo) appContext.getBean("foo"); assertTrue(foo.getBar() instanceof DevBar); System.setProperty("spring.profiles.active", "prod"); appContext = new ClassPathXmlApplicationContext("springdemo/testProfileCommon.xml", "springdemo/testDevProfile.xml", "springdemo/testProdProfile.xml"); foo = (Foo) appContext.getBean("foo"); assertTrue(foo.getBar() instanceof ProdBar); System.setProperty("spring.profiles.active", "dev"); appContext = new ClassPathXmlApplicationContext("springdemo/testProfileCommon.xml", "springdemo/*Profile.xml"); foo = (Foo) appContext.getBean("foo"); assertTrue(foo.getBar() instanceof DevBar); }
Multiple profiles
If we want DevBar
to be the implementation used for both dev and test profiles, we can include them in profile attribute as profile="dev,test"
.
In the below context file testMultiProfile.xml
we have multiple profiles sharing the beans
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <bean id="foo" class="springdemo.Foo"> <property name="bar" ref="bar"/> </bean> <beans profile="prod"> <bean id="bar" class="springdemo.ProdBar"/> </beans> <beans profile="dev,test"> <bean id="bar" class="springdemo.DevBar"/> </beans> </beans>
In both dev and test profiles, we get the same type of Bar.
public void testMultiProfile() { System.setProperty("spring.profiles.active", "dev"); ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("springdemo/testMultiProfile.xml"); Foo foo = (Foo) appContext.getBean("foo"); assertTrue(foo.getBar() instanceof DevBar); System.setProperty("spring.profiles.active", "test"); appContext = new ClassPathXmlApplicationContext("springdemo/testMultiProfile.xml"); foo = (Foo) appContext.getBean("foo"); assertTrue(foo.getBar() instanceof DevBar); }