Categories: spring

Spring @Profile Guide

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:

  • 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

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

Share
Published by

Recent Posts

Spring Boot + AngularJS + Spring Data + JPA CRUD App Example

In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL,…

7 years ago

Spring Boot Rest API Example

Spring Boot complements Spring REST support by providing default dependencies/converters out of the box. Writing RESTful services in Spring Boot…

7 years ago

Spring Boot WAR deployment example

Being able to start the application as standalone jar is great, but sometimes it might not be possible to run…

7 years ago

Spring Boot Introduction + hello world example

Spring framework has taken the software development industry by storm. Dependency Injection, rock solid MVC framework, Transaction management, messaging support,…

7 years ago

Secure Spring REST API using OAuth2

Let's secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a…

8 years ago

AngularJS+Spring Security using Basic Authentication

This post shows how an AngularJS application can consume a REST API which is secured with Basic authentication using Spring…

8 years ago