Thursday, August 11, 2022

Spring IOC - @Conditional

 Prerequisite


To create a new Spring Boot Application project in Intellij go to File -> New -> Project…



Select “Spring Initializer” and give your project a name.

I prefer “Gradle”, so I selected Gradle instead of Maven. Select your JDK, etc.

Go to the next page and under “Web” select Spring Web.


For the example that follows I named it “Springy” and set the group to “com.slinky.springy”.

Introduction


This “example” will show how to use @Conditional in an @Configuration.

You should be familiar with the basic terminology of Spring Boot dependency injection. I recommend reading “Baeldung : Spring Dependency Injection”.

This example will use dependency injection to choose a specific implementation based on some logical condition. The condition I have chosen is simple: the value of an environment variable.

I use Intelli, so edit the configuration by adding “Environment variables:”. If you don’t see “Environment variables:” choose the “Modify options ⌄” to add the field to the dialog.




Create the Following Java Classes


StringStuff.java

package com.slinky.springy;

public interface StringStuff
{
 String getString();
}


DevStringStuff.java

package com.slinky.springy;

import org.springframework.context.annotation.Conditional;

@Conditional(DevCondition.class)
public class DevStringStuff implements StringStuff
{
 @Override
 public String getString()
 {
   return "dev";
 }
}

StageStringStuff.java


package com.slinky.springy;

import org.springframework.context.annotation.Conditional;

@Conditional(StageCondition.class)
public class StageStringStuff implements StringStuff
{
 @Override
 public String getString()
 {
   return "stage";
 }
}


DevCondtion.java


package com.slinky.springy;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class DevCondition implements Condition
{
 @Override
 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
 {
   String environment = context.getEnvironment().getProperty("env");
   return environment != null && environment.contains("dev");
 }
}


StageCondition.java


package com.slinky.springy;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class StageCondition implements Condition
{
 @Override
 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
 {
   String environment = context.getEnvironment().getProperty("env");
   return environment != null && environment.contains("stage");
 }
}


Configurator.java


package com.slinky.springy;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.slinky.springy")
public class Configurator
{
 @Bean
 @Conditional(DevCondition.class)
 public StringStuff getDevStringStuff() {
   return new DevStringStuff();
 }

 @Bean
 @Conditional(StageCondition.class)
 public StringStuff getStageStringStuff() {
   return new StageStringStuff();
 }

}


SpringyApplication.java


package com.slinky.springy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication(scanBasePackages = {"com.slinky.springy"})
@RestController
public class SpringyApplication
{

 @Autowired(required = false)
 private StringStuff stuffService;

 public static void main(String[] args)
 {
   SpringApplication.run(SpringyApplication.class, args);
 }

 @GetMapping("/env")
 public String env() {
   if (null != stuffService) {
     return stuffService.getString();
   }
   return "env error";
 }

}


Conclusion


The preceding example is so that you can create a working solution that uses @Condition. I am not going to explain why it works or comment on Spring IOC. This is to help you see a working version instead of trying to decipher the documentation and tutorials you may find on the Web.

Run the Java project and open a browser window to this location:

http://localhost:8080/env

The use of an environment variable is just a simple way to create a condition. This may not be the best way to inject behavior based on a runtime environment variable.