In this tutorial I will create examples on Spring @ConditionalOnMissingBean
. 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 @ConditionalOnMissingBean
annotation lets a bean be included based on the absence 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-missing-bean.
I will update the build script 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-missing-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>
Spring 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.missing.bean;
public class SpringService {
}
Main Class
I will create a main class to run our Spring Boot application. I will not modify our main class at all, that’s why I am writing the source code of main class here.
package com.roytuts.spring.conditional.on.missing.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 SpringConditionalOnMissingBeanApp implements CommandLineRunner {
@Autowired
private SpringService springService;
public static void main(String[] args) {
SpringApplication.run(SpringConditionalOnMissingBeanApp.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println("Spring service fully qualified class name: " + springService.getClass());
}
}
Examples on @ConditionalOnMissingBean
I will create various ways of using @ConditionalOnMissingBean
annotation.
I will create a Spring Config class and use annotation @ConditionalOnMissingBean
in various ways, such as, by name, type, value, annotation and will see how it works.
The same Spring Config class will be modified to show different examples.
@ConditionalOnMissingBean – by type
You can specify by type by passing type
or if you do not pass any value then default value is by type
.
In the below example, the springService
bean is going to be created if no bean of type SpringService
is already contained in the ApplicationContext
.
package com.roytuts.spring.conditional.on.missing.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
// @ConditionalOnMissingBean
@ConditionalOnMissingBean(type = "SpringService")
public SpringService springService() {
return new SpringService();
}
}
When you run the main class you will see below output:
Spring service fully qualified class name: class com.roytuts.spring.conditional.on.missing.bean.SpringService
Now if you put @Service
annotation on SpringService
class and try to run the main class, you will see error in console because the bean already exists in the ApplicationContext
.
The bean 'springService', defined in class path resource [com/roytuts/spring/conditional/on/missing/bean/SpringConfig.class], could not be registered. A bean with that name has already been defined in file
You may also pass multiple types as @ConditionalOnMissingBean(type = { "SpringService", "AnotherSpringService" })
.
@ConditionalOnMissingBean – by value
Now I will pass by value
.
package com.roytuts.spring.conditional.on.missing.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnMissingBean(value = SpringService.class)
public SpringService springService() {
return new SpringService();
}
}
You will get the same output as you had seen for type.
You can specify multiple classes for value
as @ConditionalOnMissingBean(value = { SpringService.class, AnotherSpringService.class })
.
@ConditionalOnMissingBean – by name
I will pass bean’s name for the name
.
package com.roytuts.spring.conditional.on.missing.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnMissingBean(name = "springService")
public SpringService springService() {
return new SpringService();
}
}
Now running the main class will give the same output.
For multiple names you can use @ConditionalOnMissingBean(name = { "springService", "anotherSpringService" })
.
@ConditionalOnMissingBean – by search
You can use by search
and for this to work you have to use any of the following SearchStrategy
.
ALL - searches the entire hierarchy
ANCESTORS - searches all ancestors, but not the current context
CURRENT - searches only the current context
For our example, I will get result for SearchStrategy.ALL
and SearchStrategy.CURRENT
because no ancestor found, so I will get null pointer exception if I try to execute using SearchStrategy.ANCESTORS
.
package com.roytuts.spring.conditional.on.missing.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public SpringService springService() {
return new SpringService();
}
}
By running the main class you will get the same output.
@ConditionalOnMissingBean – by annotation
Update the Spring Config class by passing value for the annotation
.
Make sure your class does not have the annotation which is passed as a value for annotation
.
package com.roytuts.spring.conditional.on.missing.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnMissingBean(annotation = Service.class)
public SpringService springService() {
return new SpringService();
}
}
By running the main class you will see the same output.
You may also pass multiple annotations using @ConditionalOnMissingBean(annotation = { Service.class, Repository.class })
.
@ConditionalOnMissingBean – by ignored
You can ignore a class or classes, even the same class you are creating bean for.
package com.roytuts.spring.conditional.on.missing.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnMissingBean(ignored = AnotherSpringService.class)
public SpringService springService() {
return new SpringService();
}
}
To ignore multiple classes, use @ConditionalOnMissingBean(ignored = { SpringService.class, AnotherSpringService.class })
.
@ConditionalOnMissingBean – by ignoredType
In the above example I passed class or classes but here I will pass type or types of the class or classes.
package com.roytuts.spring.conditional.on.missing.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnMissingBean(ignoredType = "AnotherSpringService")
public SpringService springService() {
return new SpringService();
}
}
For multiple ignore types, you can use @ConditionalOnMissingBean(ignoredType = { "SpringService", "AnotherSpringService" })
.
@ConditionalOnMissingBean – by parameterizedContainer
Spring documentation says
Additional classes that may contain the specified bean types within their generic parameters. For example, an annotation declaring
value=Name.class
andparameterizedContainer=NameRegistration.class
would detect bothName
andNameRegistration<Name>
.
Parameterized Class
Create below class which will be used as a parameterized class into another class.
package com.roytuts.spring.conditional.on.missing.bean;
public class RequiredBean {
}
Create parameterized class with the below source code.
package com.roytuts.spring.conditional.on.missing.bean;
public class AnotherSpringService<T extends RequiredBean> {
}
Now I will update Spring Config Class as follows:
package com.roytuts.spring.conditional.on.missing.bean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
@ConditionalOnMissingBean(parameterizedContainer = AnotherSpringService.class)
public SpringService springService() {
return new SpringService();
}
@Bean
public AnotherSpringService<RequiredBean> anotherSpringService() {
return new AnotherSpringService<RequiredBean>();
}
}
Running the main class will give you the same output.
By same output for all the above cases I meant to say that you will get successfully bean created for
SpringService
.
That’s all about the @ConditionalOnMissingBean
in Spring based applications.