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.
- Spring Boot+AngularJS+Spring Data+Hibernate+MySQL CRUD App
- Spring Boot REST API Tutorial
- Spring Boot WAR deployment example
- Spring Boot Introduction + Hello World Example
- Secure Spring REST API using OAuth2
- AngularJS+Spring Security using Basic Authentication
- Secure Spring REST API using Basic Authentication
- Spring 4 Cache Tutorial with EhCache
- Spring 4 Caching Annotations Tutorial
- Spring 4 MVC+JPA2+Hibernate Many-to-many Example
- Spring 4 Email Template Library Example
- Spring 4 Email With Attachment Tutorial
- Spring 4 Email Integration Tutorial
- Spring MVC 4+AngularJS Example
- Spring MVC 4+JMS+ActiveMQ Integration Example
- Spring 4+JMS+ActiveMQ @JmsLister @EnableJms Example
- Spring 4+JMS+ActiveMQ Integration Example
- Spring MVC 4+Hibernate 4 Many-to-many JSP Example
- Spring MVC 4+Hibernate 4+MySQL+Maven integration example using annotations
- Spring MVC4 FileUpload-Download Hibernate+MySQL Example
- TestNG Mockito Integration Example Stubbing Void Methods
- Maven surefire plugin and TestNG Example
- Spring MVC 4 Form Validation and Resource Handling
Following technologies being used:
- Spring 4.0.6.RELEASE
- Maven 3
- JDK 1.6
- Eclipse JUNO Service Release 2
Project directory structure
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.
Step 1: Provide Spring dependencies in Maven pom.xml
<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>
Step 2: Create Spring Configuration Class
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
-
Setting
spring.profiles.active
property (via JVM arguments, environment variable or Servlet context parameter in web.xml in case of web applications) - ApplicationContext.getEnvironment().setActiveProfiles(“ProfileName”);
Based on your environment you will provide the value of profile, and the beans dependent on that profile will be registered in Spring container.
Step 3: Create Main to run as Java Application
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.
XML Based Spring Profile Configurtrion
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.
Download Source Code
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.