Spring @ConditionalOnMissingBean Example

Conditional On Missing Bean

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 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-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>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>

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.

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.

@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 nametypevalue, 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.

@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.

@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.

@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.

@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.

@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.

@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.

@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 and parameterizedContainer=NameRegistration.class would detect both Name and NameRegistration<Name>.

Parameterized Class

Create below class which will be used as a parameterized class into another class.

public class RequiredBean {
}

Create parameterized class with the below source code.

public class AnotherSpringService<T extends RequiredBean> {
}

Now I will update Spring Config Class as follows:

@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.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *