In this post we will explore Spring @Profile
annotation and use it to make different set of beans or configuration available conditionally on different environments. We will also discuss corresponding XML based profile configuration for comparison.
Let’s imagine you have an application which includes database-interaction. You might want to configure one dataSource (for MySQL e.g.) for Development environment while completely different dataSource (for ORACLE e.g.) for Production.
Using Spring Profiles
, you can easily manage such setup. We will explore this example use-case in this post.
Following technologies being used:
Following will be the final project directory structure for this example:
Let’s now add the content mentioned in above structure explaining each in detail.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.websystique.spring</groupId> <artifactId>Spring4ProfilesExample</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <name>Spring4ProfilesExample</name> <properties> <springframework.version>4.0.6.RELEASE</springframework.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${springframework.version}</version> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>
Spring configuration class are the ones annotated with @Configuration
. These classes contains methods annotated with @Bean
. These @Bean annotated methods generates beans managed by Spring container.
package com.websystique.spring.configuration; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages = "com.websystique.spring") public class AppConfig { @Autowired public DataSource dataSource; }
Above Configuration just have one property to be auto-wired. Now what we will show here is that this dataSource bean can be injected with different beans on different environment (MySQL dataSource on Development & ORACLE for Production e.g.).
package com.websystique.spring.configuration; import javax.sql.DataSource; public interface DatabaseConfig { DataSource createDataSource(); }
Simple Interface to be implemented by all possible environment configurations.
package com.websystique.spring.configuration; import javax.sql.DataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.jdbc.datasource.DriverManagerDataSource; @Profile("Development") @Configuration public class DevDatabaseConfig implements DatabaseConfig { @Override @Bean public DataSource createDataSource() { System.out.println("Creating DEV database"); DriverManagerDataSource dataSource = new DriverManagerDataSource(); /* * Set MySQL specific properties for Development Environment */ return dataSource; } }
package com.websystique.spring.configuration; import javax.sql.DataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.jdbc.datasource.DriverManagerDataSource; @Profile("Production") @Configuration public class ProductionDatabaseConfig implements DatabaseConfig { @Override @Bean public DataSource createDataSource() { System.out.println("Creating Production database"); DriverManagerDataSource dataSource = new DriverManagerDataSource(); /* * Set ORACLE specific properties for Production environment */ return dataSource; } }
Both DevDatabaseConfig and ProductionDatabaseConfig are simple configuration classes implementing DatabaseConfig interface. What special about these classes are that they are annotated with @Profile
annotation.
@Profile
annotation on a component registers that component in Spring context only when that profile is active. Profile activation means this profile value should be available either by
spring.profiles.active
property (via JVM arguments, environment variable or Servlet context parameter in web.xml in case of web applications) Based on your environment you will provide the value of profile, and the beans dependent on that profile will be registered in Spring container.
package com.websystique.spring; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class AppMain { public static void main(String args[]){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //Sets the active profiles context.getEnvironment().setActiveProfiles("Development"); //Scans the mentioned package[s] and register all the @Component available to Spring context.scan("com.websystique.spring"); context.refresh(); context.close(); } }
Notice how we have set the active profiles to be used on runtime. context.scan("package")
scans the mentioned package and registers all the @Component but when it encounters the @Profile annotation on a bean/configuration, it compare the profile value with the one supplied in environment. If the value mathces, it registers that bean else it skips it. In our case it’s the DevDatabaseConfig dataDource which will be injected in AppConfig.dataSource.
Run above program , you will see following output:
Creating DEV database
That’s it.
Now, Let’s discuss Spring Profile once more, this time using XML configuration
Replace DevelopmentDatabaseConfig by dev-config-context.xml (src/main/resources/dev-config-context.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/websystique" /> <property name="username" value="myuser" /> <property name="password" value="mypassword" /> </bean> </beans>
Replace ProductionDatabaseConfig by prod-config-context.xml (src/main/resources/prod-config-context.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value=" oracle.jdbc.driver.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@PRODHOST:PRODPORT/websystique" /> <property name="username" value="myproduser" /> <property name="password" value="myprodpassword" /> </bean> </beans>
Replace AppConfig by app-config.xml (src/main/resources/app-config.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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.websystique.spring"/> <beans profile="Development"> <import resource="dev-config-context.xml"/> </beans> <beans profile="Production"> <import resource="prod-config-context.xml"/> </beans> </beans>
Based on actual profile in use, corresponding config-context.xml file will be loaded, other one will be ignored.
Let’s also tweak the main:
package com.websystique.spring; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AppMain { public static void main(String args[]){ AbstractApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml"); //Sets the active profiles context.getEnvironment().setActiveProfiles("Development"); /* * Perform any logic here */ context.close(); } }
Run it. You will see the same output as with Annotation based setup.
References
If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus & Twitter as well? I would love to hear your thoughts on these articles, it will help improve further our learning process.
In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL,…
Spring Boot complements Spring REST support by providing default dependencies/converters out of the box. Writing RESTful services in Spring Boot…
Being able to start the application as standalone jar is great, but sometimes it might not be possible to run…
Spring framework has taken the software development industry by storm. Dependency Injection, rock solid MVC framework, Transaction management, messaging support,…
Let's secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a…
This post shows how an AngularJS application can consume a REST API which is secured with Basic authentication using Spring…
View Comments
Hi,
On the below code, we have main so we can setActiveProfile Development, But In Spring MVC project, We don't have main method. So Where we can set the setActiveprofile, If i want to use into my project
public static void main(String args[]){
AbstractApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");
//Sets the active profiles
context.getEnvironment().setActiveProfiles("Development");
/*
* Perform any logic here
*/
context.close();
Spring honors two separate properties when determining which profiles are active:
spring.profiles.active and spring.profiles.default. If spring.profiles.active
is set, then its value determines which profiles are active. But if spring
.profiles.active isn’t set, then Spring looks to spring.profiles.default. If neither
spring.profiles.active nor spring.profiles.default is set, then there are no
active profiles, and only those beans that aren’t defined as being in a profile are created.
There are several ways to set these properties:
As initialization parameters on DispatcherServlet
As context parameters of a web application
As JNDI entries
As environment variables
As JVM system properties
Using the @ActiveProfiles annotation on an integration test class