Conditional On Bean
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 12/19, Maven 3.6.3/3.8.5, Spring Boot 2.1.7 – 2.4.5/3.1.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>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.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.
public class SpringService {
}
Examples on @ConditionalOnBean
I will create various ways of using @ConditionalOnBean
annotation on the bean.
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.
@Component
public class RequiredBean {
}
Bean – AnotherRequiredBean
@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.
@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
.
@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.
@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.
@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.
@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.
@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.