What Does @SpringBootApplication Actually Do? A Deep Dive into Spring Boot’s Core Annotation
This article dissects the @SpringBootApplication annotation, explaining how it combines @SpringBootConfiguration, @EnableAutoConfiguration, and @ComponentScan, and walks through the auto‑configuration mechanism, conditional annotations, and common interview questions with concrete code examples.
Composite Annotation @SpringBootApplication
Defines a single annotation that bundles three core Spring Boot annotations:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // marks a configuration class
@EnableAutoConfiguration // enables auto‑configuration (core)
@ComponentScan(
excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
}
)
public @interface SpringBootApplication {
// ...
}@SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}Acts as a wrapper around @Configuration, allowing the boot starter class to define @Bean methods.
@ComponentScan
@ComponentScan(
excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
}
)Scans and registers beans. The default scan range is the package of the startup class and all its sub‑packages.
Project structure example (default scan):
com.example.blog
├── Application.java // @SpringBootApplication
├── controller // ✅ scanned
├── service // ✅ scanned
├── repository // ✅ scanned
└── config // ✅ scanned
// External package
com.example.external // ❌ not scanned without extra configurationCustom scan example:
@SpringBootApplication(scanBasePackages = {"com.example.blog", "com.example.common"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}Exclude scan example:
@SpringBootApplication
@ComponentScan(excludeFilters = {
@ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.example.test.*")
})
public class Application {
// ...
}@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // registers the package name
@Import(AutoConfigurationImportSelector.class) // imports auto‑configuration
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}Two core parts:
@AutoConfigurationPackage – records the package of the startup class for later auto‑configuration use (e.g., JPA entity scanning).
@Import(AutoConfigurationImportSelector.class) – the heart of auto‑configuration; loads all auto‑configuration classes listed under the EnableAutoConfiguration key in META-INF/spring.factories.
public class AutoConfigurationImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1. Check if auto‑configuration is enabled
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 2. Load auto‑configuration metadata
AutoConfigurationEntry entry = getAutoConfigurationEntry(annotationMetadata);
// 3. Return the class names to import
return StringUtils.toStringArray(entry.getConfigurations());
}
// ... helper methods omitted for brevity
}Loading flow (simplified):
@EnableAutoConfiguration
│
▼
AutoConfigurationImportSelector
│
▼
Load META-INF/spring.factories
│
▼
key = org.springframework.boot.autoconfigure.EnableAutoConfiguration
│
▼
~100+ auto‑configuration classes (e.g., DataSourceAutoConfiguration)
│
▼
Conditional annotations filter
│
▼
Final effective auto‑configurationAuto‑Configuration Mechanism
spring.factories file
# META-INF/spring.factories (partial)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfigurationConditional Annotations
@ConditionalOnClass– effective only when a specific class is present on the classpath. @ConditionalOnMissingClass – effective only when a specific class is absent. @ConditionalOnBean – effective only when a particular bean exists in the container. @ConditionalOnMissingBean – effective only when a particular bean is missing. @ConditionalOnProperty – effective only when a property is defined in configuration files. @ConditionalOnWebApplication – effective only in a web application context.
Concrete Example: DataSourceAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({DataSourcePoolMetadataProvidersConfiguration.class,
DataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class DataSourceConfiguration {
// create DataSource bean
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type",
havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true)
static class Hikari {
// HikariCP pool configuration
}
} @ConditionalOnClass(DataSource.class)– loads only if DataSource is on the classpath. @ConditionalOnMissingBean(DataSource.class) – applies when the user has not defined a DataSource bean. @ConditionalOnProperty(name = "spring.datasource.type") – activates when the spring.datasource.type property is set.
Excluding Specific Auto‑Configuration
YAML configuration:
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfigurationAnnotation configuration:
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class Application {
// ...
}Why @ComponentScan Defaults to the Startup Package
@ComponentScanscans the package where the annotated class resides. Since @SpringBootApplication is placed on the main class, the default scan range is that package and its sub‑packages. The range can be overridden with the scanBasePackages attribute.
Overall Startup Flow Diagram
@SpringBootApplication
│
├── @SpringBootConfiguration → @Configuration → startup class is also a config class
│
├── @ComponentScan → scans startup class package and sub‑packages → registers @Service/@Controller
│
└── @EnableAutoConfiguration
│
├── @AutoConfigurationPackage → records package name
│
└── @Import(AutoConfigurationImportSelector)
│
▼
Loads META‑INF/spring.factories
│
▼
~100+ auto‑configuration classes
│
▼
Conditional annotation filtering
│
▼
Final effective auto‑configurationSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Coder Trainee
Experienced in Java and Python, we share and learn together. For submissions or collaborations, DM us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
