Creating Conditional Beans with ConditionalProperty in Spring Boot

Caner Ünal
Codimis
Published in
4 min readMar 12, 2024

In a Spring Boot application, beans are the fundamental building blocks. They are Java objects managed by the Spring IoC (Inversion of Control) container. Conditional beans take the concept of beans a step further by allowing developers to define conditions for the instantiation of beans. This ensures that beans are only created when specific criteria are met, promoting a more tailored and efficient application configuration.

In this post, I want to show an example with written by ConditionalProperty annotation in Spring. Also, other annotations will mentioned in this article.

A usage scenario

Let’s say we are currently using a SOAP web service for our business requirements and this SOAP web service will be deprecated. We need to replace this service with REST equivalent. However, there is a requirement that comes to our development team.

When this service is upgraded to REST, the legacy one will must live for sometime. Anytime we can need to switch the old one and it can be used. For that purpose, we can define a parameter to application and create bean according to our parameter value. This feature is enabled by ConditionalProperty annotation.

Conditional Property in Detail

Below there is a practical example to demonstrate the usage of conditional property in a Spring Boot command line application. I need two beans SoapWebService and RestWebService beans are created in the application. Let’s imagine SoapWebServiceImpl exists in the app before. RestWebServiceImpl is created for this scenario. This two beans have one simple method.

@Service
public class SoapWebServiceImpl implements IntegrationWebService {
@Override
public void sendData() {
System.out.println("SoapWebService sending data...");
}
}

@Service
public class RestWebServiceImpl implements IntegrationWebService {
@Override
public void sendData() {
System.out.println("RestWebService sending data...");
}
}

I’m adding a property to application.properties file, which name is integration.service.type

spring.main.web-application-type=NONE
integration.service.type=rest

After adding property to application.properties file, ConditionalProperty annotation added to the service beans. name property’s value is must be integration.service.type. havingValue property is set for which

@Service
@ConditionalOnProperty(name = "integration.service.type", havingValue = "rest")
public class RestWebServiceImpl implements IntegrationWebService

@Service
@ConditionalOnProperty(name="integration.service.type", havingValue = "soap")
public class SoapWebServiceImpl implements IntegrationWebService

Let’s start our CommandLineRunner application. You can check SpringBootApplication main class code below. IntegrationWebService is injected to main class. sendData() method is called at the end of the run method.

@SpringBootApplication
public class ConditionalbeanexampleApplication implements CommandLineRunner {

@Autowired
private IntegrationWebService webService;

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

@Override
public void run(String... args) throws Exception {
System.out.println("Application is running");
webService.sendData();
}
}

When I run this application, RestWebServiceImpl bean is created because current value of this property is rest. The output of the start is below. When this property value is changed to soap, SoapWebServiceImpl is created.

Application is running
RestWebService sending data...

Other Conditional Annotations

Spring Boot provides a set of conditional annotations that developers can leverage to control bean creation based on various conditions. Some notable conditional annotations include:

@ConditionalOnClass: This annotation ensures that the annotated bean is created only if a specified class is present in the classpath.

@Configuration
@ConditionalOnClass(ExampleDependency.class)
public class ExampleAutoConfiguration {
// ...
}

@ConditionalOnMissingClass: This annotation, on the other hand, creates the bean only if a specified class is missing in the classpath.

@Configuration
@ConditionalOnMissingClass("com.example.ExampleDependency")
public class FallbackConfiguration {
//...
}

@ConditionalOnBean: Creates the bean only if a specified bean is present in the application context.

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfiguration {

@Bean
public MyBean myBean() {
// This bean alwaws created
return new MyBean();
}

@Bean
@ConditionalOnBean(MyBean.class)
public AnotherBean anotherBean() {
// This bean created if application context has MyBean
return new AnotherBean();
}
}

@ConditionalOnMissingBean: This annotation creates the bean if a specified bean is missing from the application context.

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfiguration {

@Bean
public MyBean myBean() {
// This bean alwaws created
return new MyBean();
}

@Bean
@ConditionalOnMissingBean(MyBean.class)
public AnotherBean anotherBean() {
// This bean created if application context has not MyBean
return new AnotherBean();
}
}

These annotations offer a powerful way to conditionally control the creation of beans, making the application more modular and adaptable to different environments.

Conclusion

Conditional beans in the Spring Boot Framework provide a powerful mechanism for dynamically configuring and adapting your application based on specific conditions. By leveraging conditional annotations, developers can control the instantiation of beans, making the application more modular and efficient. Whether it’s based on class presence, property values, or bean existence, conditional beans enhance the flexibility of Spring Boot applications, allowing them to seamlessly adapt to various runtime scenarios.

--

--