Introduction
I will create examples on Spring @ConditionalOnBean
. Anywhere you define a Spring bean, you can optionally add a condition. Only if the specified condition is satisfied then only bean will be added to the application context. To declare a condition, you can use any of the @Conditional…
annotations. The @ConditionalOnBean
annotation let a bean be included based on the presence of specific beans. By default Spring will search entire hierarchy (SearchStrategy.ALL
).
Prerequisites
Java at least 1.8, Maven 3.6.3, Spring Boot 2.1.7 – 2.4.5
Project Setup
Create a maven based project in your favorite IDE or tool with the project name as spring-conditional-on-bean.
I will update the build file (pom.xml) as follows to include the spring boot dependencies.
<?xml version="1.0" encoding="UTF-8"?>
<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.roytuts</groupId>
<artifactId>spring-conditional-on-bean</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Service Class
I will create simple service class without any methods in it. Ideally this service class will have some methods to perform your project’s business operations.
package com.roytuts.spring.conditional.on.bean;
public class SpringService {
}
Examples on @ConditionalOnBean
I will create various ways of using @ConditionalOnBean
annotation.
Simple Beans
I will create two beans which will be required to call on @ConditionalOnBean
annotation because these annotated bean will be executed only when the required bean is found.
Bean – RequiredBean
I have used annotation @Component
to get advantage of autowire.
package com.roytuts.spring.conditional.on.bean;
import org.springframework.stereotype.Component;
@Component
public class RequiredBean {
}
Bean – AnotherRequiredBean
package com.roytuts.spring.conditional.on.bean;
import org.springframework.stereotype.Component;
@Component
public class AnotherRequiredBean {
}
Examples – @ConditionalOnBean
I will create a Spring Config class and use annotation @ConditionalOnBean
in various ways, such as, by name, type, value, search and will see how it works.
I will modify our Spring Config class for each type of example.
I will also create a main class to run our application. The source of the main class is given below. I will not modify the main class but I will run our main class after each modification to the Spring Config class.
package com.roytuts.spring.conditional.on.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringConditionalOnBeanApp implements CommandLineRunner {
@Autowired
private SpringService springService;
public static void main(String[] args) {
SpringApplication.run(SpringConditionalOnBeanApp.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println("Spring service fully qualified class name: " + springService.getClass());
}
}
@ConditionalOnBean – by value
Here I will show @ConditionalOnBean
by value in Spring Config class.
I will pass the class for the value value
.
package com.roytuts.spring.conditional.on.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnBean(value = RequiredBean.class)
public SpringService springService() {
return new SpringService();
}
}
Run the main class to see the result as shown below in the console.
Spring service fully qualified class name: class com.roytuts.spring.conditional.on.bean.SpringService
Therefore to build a new instance of the SpringService
class your RequiredBean
class must exist.
@ConditionalOnBean – by name
I will now use by passing the bean name for the value name
. Here I am passing single bean names but you can also pass multiple bean names and I will show on this after this example.
As I have annotated class RequiredBean
with @Component
and by default bean name is resolved as class name with initial letter in lower case, so you don’t need to define it separately.
package com.roytuts.spring.conditional.on.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnBean(name = "requiredBean")
public SpringService springService() {
return new SpringService();
}
}
Now run the main class to see the below output:
Spring service fully qualified class name: class com.roytuts.spring.conditional.on.bean.SpringService
Now if you change as @ConditionalOnBean(name = "RequiredBean")
then you will see below error in the console because bean with name RequiredBean
does not exist.
Bean method 'springService' in 'SpringConfig' not loaded because @ConditionalOnBean (names: RequiredBean; SearchStrategy: all) did not find any beans named RequiredBean
@ConditionalOnBean – by name
I had passed single bean name in the above example and now I will pass multiple names and check the results.
package com.roytuts.spring.conditional.on.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnBean(name = { "requiredBean", "anotherRequiredBean" })
public SpringService springService() {
return new SpringService();
}
}
You will find same output in the console with new SpringService
instance.
@ConditionalOnBean – by type
Next I will pass value by type
in the @ConditionalOnBean
annotation.
package com.roytuts.spring.conditional.on.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnBean(type = "com.roytuts.spring.conditional.on.bean.RequiredBean")
public SpringService springService() {
return new SpringService();
}
}
You will get the same output as for the by name.
@ConditionalOnBean – by search
Strategy to decide if the application context hierarchy (parent contexts) should be considered. It the search strategy. The default search strategy is ALL. Others are ANCESTORS and CURRENT.
package com.roytuts.spring.conditional.on.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnBean(search = SearchStrategy.CURRENT, type = "com.roytuts.spring.conditional.on.bean.RequiredBean")
public SpringService springService() {
return new SpringService();
}
}
You will get the same output as for the by name.
@ConditionalOnBean
does not prevent@Configuration
classes from being created.