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.

Coder Trainee
Coder Trainee
Coder Trainee
What Does @SpringBootApplication Actually Do? A Deep Dive into Spring Boot’s Core Annotation

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 configuration

Custom 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‑configuration

Auto‑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.WebMvcAutoConfiguration

Conditional 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.DataSourceAutoConfiguration

Annotation configuration:

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class Application {
    // ...
}

Why @ComponentScan Defaults to the Startup Package

@ComponentScan

scans 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‑configuration
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend Developmentspring-bootComponentScanAuto-configuration@SpringBootApplicationConditionalOnClass
Coder Trainee
Written by

Coder Trainee

Experienced in Java and Python, we share and learn together. For submissions or collaborations, DM us.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.