Spring Boot – Using Conditional Beans based on Profiles

As I mentioned in the little walkthrough of Spring Boot Profiles you sometimes have to implement a different behaviour for special purposes.
One common example for this are different test stages within different types of databases, ports or something like that.

We handled, how we can change the environments of our software like the port or the connection to a database. But what should we do if we want to have and entire different implementation?

Let´s say, during your development you always want to automatically have a logged in user in your backend because you don´t want to type through your entire login logic everytime you just want to check a new implementation.

Exactly for this purpose we can use the ConditionalOn* Annotation of Spring Boot.

Project Setup

A good basic for understanding what we want to do with the profiles is by looking at this little beauty. But let´s just create a very simple example.

We just want to return an object via Rest, which values can differ depending on the profile used for building the project.

Property files

Just setup a Spring Boot Project, with 3 different application.yml (or .properties), that would look like this:

application.yml

spring:
  profiles:
    active: '@spring.profile@'

application-dev.yml

mode : dev

application-prod.yml

mode : prod

If you use the *.properties way just replace the : with = and write spring.profiles.active=’@spring.profile’

Basic Classes

Following I´ll explain to you the basic classes we need. That´s the obvious and simple stuff I think, so let´s get through it quickly.

Bean for Data Storing

package com.javadevcorner.profilingExample;

import org.springframework.stereotype.Component;

/**
 *
 * @author javadevcorner.com
 */
@Component
public class WelcomeMessage {

    private String message;
    private String author;

   //setter and getter stuff
    
}

That´s just a simple bean, which we use to store some data.

Rest Resource

package com.javadevcorner.profilingExample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
 *
 * @author javadevcorner.com
 */
@RestController
public class StandardResource {

    @Autowired
    private WelcomeMessage welcomeMessage;

    @GetMapping
    @ResponseBody
    public WelcomeMessage sayHelloToMyLittleFriend() {
        return welcomeMessage;
    }
}

Of course we need a little Rest Resource that is also a very simple one.
Just returning the injected WelcomeMessage object.

StartupService

To accomplish our different behaviours during build time, we need an interface as a contract to the Application Context

package com.javadevcorner.profilingExample;

/**
 *
 * @author javadevcorner.com
 */
public interface StartUpService {
    
    public void setupWelcomeMessage();
    
}

Just a plain old java interface. 

Implement Behaviours

Now, after we have done the basic job, we need to do the “little magic” of our development. Don´t be afraid, it is much more simpler than you may think.

Bind to Application Startup

As we said, we want to bind our behaviours to the startup point of the application. We´ll accomplish this by call our StartupService on the Application Context

package com.javadevcorner.profilingExample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 *
 * @author javadevcorner.com
 */
@SpringBootApplication
public class ProfilingExampleApplication {

  public static void main(String[] args) {
            ConfigurableApplicationContext ctx = SpringApplication.run(ProfilingExampleApplication.class, args);
            ctx.getBean(StartUpService.class).setupWelcomeMessage();
  }
}

As you can see, we now have our interface on the Application Context.

On Startup Spring Boot will search for a bean that implements the Interface. 
But we will have to of this beans. We just tell Spring Boot which to use on Startup.

Implementing Behaviour for Dev

The first behaviour we want to have is, when we start with the dev profile.

package com.javadevcorner.profilingExample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

/**
 *
 * @author javadevcorner.com
 */
@Component
@ConditionalOnProperty(name = "mode", havingValue = "dev")
public class StartUpServiceBeanDev implements StartUpService {

    @Autowired
    private WelcomeMessage welcomeMessage;

    @Override
    public void setupWelcomeMessage() {
        welcomeMessage.setAuthor("Bean Dev");
        welcomeMessage.setMessage("I was made from Bean Dev");
    }

}

At first we override the interface StartUpService and their method.
At first look at line 12. We define which Conditional should be called based on the Property of our config file. Again we inject the WelcomeMessage.

Implementing Behaviour for Prod

As you may can estimate, we will implement a similar class for prod profile.

package com.javadevcorner.profilingExample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

/**
 *
 * @author javadevcorner.com
 */
@Component
@ConditionalOnProperty(name = "mode", havingValue = "prod")
public class StartUpServiceBeanProd implements StartUpService {

    @Autowired
    private WelcomeMessage welcomeMessage;

    @Override
    public void setupWelcomeMessage() {
        welcomeMessage.setAuthor("Bean Prod");
        welcomeMessage.setMessage("I was made from Bean Prod");
    }

}

Runtime

Start the Application

To start the application use the command line interface and type the spring boot run command with the profile you want to use.

mvn spring-boot:run -Dspring.profiles.active=dev

or

mvn spring-boot:run -Dspring.profiles.active=prod

Output for dev

Output for prod

 

Thanks for reading and have fun using the Spring Boot ConditionalOn annotation

Feel free to share

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.