Switching Database Profiles AT Runtime Using Spring Profiles

Databases play a major role in storing persistence data in modern software applications. We mostly prefer to have separate database configuration for our application running in different environments. For example, our development environment is likely to have a different database than our production environment.

One way to configure this is to have separate configuration classes or XML for each datasource and make the decision at build-time. One of the drawbacks of this approach is that a rebuild is required when switching for one environment to another. Spring provides a more clean approach using Spring profiles, where the decision is made at runtime.

Configuring Profiles with Java Configuration

We can define our profile beans using @Profile annotation as shown below:

@Configuration
public class DBProfileConfig {

    @Profile("dev")
    @Bean(name="datasource")
    public DataSource devDataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl("jdbc:mysql://cubedev.cubearticle.com:3306/cubedev");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUsername("cubedev");
        dataSource.setPassword("dev123");
        dataSource.setInitialSize(10);
        dataSource.setMaxActive(20);
        return dataSource;
    }
    
    @Profile("prod")
    @Bean(name="datasource")
    public DataSource prodDataSource() {
        JndiObjectFactoryBean jndiFactory = new JndiObjectFactoryBean();
        jndiFactory.setJndiName("jdbc/cubeprod");
        jndiFactory.setResourceRef(true);
        jndiFactory.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource) jndiFactory.getObject()
    }
}

Before creating the datasource bean, Spring will check for the active profile. Only the bean that is in the active profile will be created and the other will be ignored.


Configuring Profiles with XML

We can also configure Spring profile beans using xml configuration files using the 'profiles' attribute in the <beans> element. We can either use separate configuration files for each datasource configuration or we can nest the <beans> element in the root <beans> element. The example below shows the nested <beans> approach:

<?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.xsd
            http://www.springframework.org/schema/context 
	    http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	
    <beans profile="dev">
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://cubedev.cubearticle.com:3306/cubedev" />
            <property name="username" value="cubedev" />
            <property name="password" value="dev123" />
            <property name="initialSize" value="10" />
            <property name="maxActive" value="20" />
        </bean>
    </beans>
	
    <beans profile="prod">
        <jee:jndi-lookup id="dataSource"
            jndi-name="jdbc/cubeprod"
            resource-ref="true"
            proxy-interface="javax.sql.DataSource" />
    </beans>
</beans>

Activating a Profile

Spring makes use of two different properties to determine the active profile. The properties are:

  • spring.profiles.default
  • spring.profiles.active

If 'spring.profiles.active' is set, its value is considered as the active profile, else Spring looks for the value of 'spring.profiles.default'. If none of them are set, there is no active profile and the beans that are in any profile will not be created.

These properties can be set in many ways:

  • Using context parameters in web.xml
  • Using initialization parameters in DispatcherServlet
  • Using JNDI entries
  • Using JVM properties
  • Using environment variables

The code snippet below shows how to set the 'spring.profiles.default' property using initialization parameters in DispatcherServlet. With 'dev' as default we can use the environment properties to set the 'spring.profiles.active' property to 'prod' in production environment.

<servlet>
    <servlet-name>cubearticle</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>spring.profiles.default</param-name>
        <param-value>dev</param-value>
    </init-param>
</servlet>
POPULAR ARTICLES

Creating Conditional Beans in Spring

The concept of condition beans enables Spring to restrict the creation of any bean depending on the evaluation of a condition. These beans get created only when a preset condition is evaluated as true

View Article

Accepting Request Param and Path Variable in Spring Controller

Spring MVC provides various ways through which a client browser can pass data to the Controller. In this article we will discuss about accepting Request Parameters and Path Variables in Spring Contr..

View Article

Generate Namespace & Schema Information using JAXB

Most xml documents used in enterprise applications makes use of namespace to avoid element name conflicts. This article talks about generating these namespace and schema information when marshaling...

View Article

Switching Database Profile using Spring Profiles

We are most likely to have separate db configuration for different environment like development and production environment. Spring profiles provide a convenient way to switch db profiles at runtime.

View Article

SQL and its Sub-Languages

SQL (Structured Query Language) is a language understood by most modern databases. It is an ANSI (American National Standard Institute) standard language which is used to manipulate databases.

View Article

Introducing JUnit Rule

Junit Rules allows developers to add additional functionalities that can applied to all test methods in a test class. It is similar to the concept of custom test runners but with reduced restrictions.

View Article

Addressing Ambiguity in Spring Autowiring

Spring autowiring is powerful concept, but we should be very cautious while using it. We may end up in creating ambiguity while autowiring beans, which will cause autowiring to fail.

View Article

Creating and Using Synonym in Oracle Database

Synonyms are database objects used to provide duplicate names to existing objects in the database. It is just an alternate name used to hide the original name of the object.

View Article

Creating and Using Sequence in Oracle Database

A sequence is used to auto-generate numbers in ascending or descending order which can serve as a primary key or a part of it (in case of composite key).

View Article

Creating and Manipulating Constraints in Oracle Database

Constraints are used to impose certain rules on columns to avoid invalid data entry into the table. If any of the constraint is violated the operation fails.

View Article

Integrating Log4J with Perf4J for Performance Logging

Perf4j is an open source logging framework used primarily for monitoring performance statistics in java applications. Log4j has the ability to integrate with perf4j to capture performance data.

View Article

Tagging in GIT

Tagging allows us to mark a specific point in the commit history or snapshot. A tag is typically used to mark a project release. This article shows how to create tags in Git.

View Article