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-web
is on the classpath, it auto-configures DispatcherServlet, Jackson, Tomcat, etc. - If a developer defines their own
ObjectMapper
bean, 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
JacksonAutoConfiguration
class 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
ObjectMapper
bean, Spring checks whether any otherObjectMapper
bean is already defined. - If the developer already defined one, Spring skips this bean.
- If no
ObjectMapper
bean 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
ObjectMapper
bean → 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.