Spring Boot’s auto-configuration mechanism simplifies application setup by automatically configuring beans based on the presence of classes, beans, or properties. Two key annotations that power this mechanism are:
@ConditionalOnClass@ConditionalOnMissingBean
Understanding how these work is critical to mastering Spring Boot internals and customizing behavior effectively.
1. What is Auto-Configuration in Spring Boot?
Spring Boot provides opinionated defaults by scanning the classpath and application context and automatically configuring components if certain conditions are met.
For example:
- If
spring-boot-starter-webis on the classpath, it auto-configures DispatcherServlet, Jackson, Tomcat, etc. - If a developer defines their own
ObjectMapperbean, the default one is not created.
This is made possible using conditional annotations inside auto-configuration classes.
2. Introduction to @ConditionalOnClass
Used to conditionally load a bean or configuration only if a specific class is present on the classpath.
Typical Usage:
@Configuration
@ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper")
public class JacksonAutoConfiguration {
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
}
How it Works:
- When Spring Boot starts, it checks whether the specified class (
ObjectMapper) is present in the classpath. - If it’s not present, the
JacksonAutoConfigurationclass is skipped entirely.
Use Case:
- Avoid configuring unused features
- Only configure if dependencies are present (e.g., don’t configure MongoDB beans if MongoDB driver is missing)
3. Introduction to @ConditionalOnMissingBean
Prevents Spring Boot from creating a bean if one already exists in the application context.
Typical Usage:
@Bean
@ConditionalOnMissingBean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
How it Works:
- Before registering the
ObjectMapperbean, Spring checks whether any otherObjectMapperbean is already defined. - If the developer already defined one, Spring skips this bean.
- If no
ObjectMapperbean exists, Spring will register this one.
Use Case:
- Allow developers to override default beans
- Avoid bean conflicts in application context
4. How These Two Work Together in Auto-Configuration
Auto-configuration classes combine these annotations to provide flexible, safe, and conditional bean creation.
Example: Jackson Auto-Configuration (Simplified)
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ObjectMapper.class) // Load only if Jackson is on classpath
public class JacksonAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ObjectMapper.class) // Only create if not already defined
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
}
Flow:
- Spring Boot sees
@ConditionalOnClass(ObjectMapper.class)and checks if Jackson is in classpath. - If present, it proceeds to register the configuration class.
- Then it evaluates the bean definition:
- If the developer already defined an
ObjectMapperbean → Spring skips it. - If not → Spring creates and registers the default one.
- If the developer already defined an
This provides out-of-the-box functionality, while still allowing custom overrides.
5. How Auto-Configuration Classes Are Loaded
The role of spring.factories or META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
Auto-configuration classes are listed in:
- For Spring Boot < 2.7:
META-INF/spring.factories - For Spring Boot 3.x+:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
Example entry:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.autoconfigure.MyAutoConfiguration
When Spring Boot starts:
- It scans the auto-configuration entries.
- Loads each class.
- Applies the conditional annotations to decide whether to apply it.
6. Internals: Conditional Annotations via @Conditional
All @ConditionalOnXxx annotations are meta-annotations on @Conditional.
Let’s see how:
@ConditionalOnClass is defined as:
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}
@ConditionalOnMissingBean is defined as:
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {
Class<?>[] value() default {};
}
hese annotations delegate their logic to:
OnClassCondition→ checks classpathOnBeanCondition→ checks the ApplicationContext for beans
7. Visual Flow of Spring Boot Auto-Configuration
Application Startup
│
┌──────────▼────────────┐
│ Scan AutoConfig Imports│
└──────────┬────────────┘
▼
For Each Auto-Config Class:
│
┌─────────────┼─────────────────────┐
▼ ▼ ▼
Check @ConditionalOnClass Check @ConditionalOnMissingBean
│ │ │
If true If true Create and register Bean
│ │
▼ ▼
Apply Configuration
8. Example: Creating Your Own Auto-Configuration with Conditions
Step 1: Custom Auto-Config Class
@Configuration
@ConditionalOnClass(MyService.class)
public class MyServiceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService() {
return new MyService();
}
}
Step 2: Register in spring.factories (Spring Boot < 3.0)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.autoconfig.MyServiceAutoConfiguration
Step 3: Use in Application
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
If you don’t define MyService, it’s auto-configured. If you define it manually, auto-configuration backs off.
