Backend Development 12 min read

Analysis of SpringBoot's @SpringBootApplication Annotation

The article dissects Spring Boot’s @SpringBootApplication annotation, revealing it as a composite of seven meta‑annotations—including @SpringBootConfiguration, @EnableAutoConfiguration and @ComponentScan—and explains the underlying registrar, import selector, metadata loading, and exclusion mechanisms that together drive Spring Boot’s automatic configuration process.

vivo Internet Technology
vivo Internet Technology
vivo Internet Technology
Analysis of SpringBoot's @SpringBootApplication Annotation

The article, authored by the vivo Internet Server Team, provides a detailed analysis of the @SpringBootApplication annotation used in Spring Boot projects, explaining its impact on startup and auto‑configuration.

@SpringBootApplication is a composite annotation that aggregates seven other annotations. Its source code is shown below:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ...
}

The seven constituent annotations are:

@Target(ElementType.TYPE) – limits the annotation to classes or interfaces.

@Retention(RetentionPolicy.RUNTIME) – makes the annotation available at runtime.

@Documented – ensures the annotation is included in Javadoc.

@Inherited – allows subclasses to inherit the annotation.

@SpringBootConfiguration – itself a meta‑annotation that combines @Configuration , turning the class into a configuration source.

@EnableAutoConfiguration – imports auto‑configuration classes based on classpath metadata.

@ComponentScan – triggers component scanning for @Component , @Repository , etc., within the package of the annotated class (or specified basePackages ).

The source of @SpringBootConfiguration is:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

The core of @EnableAutoConfiguration is shown below:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
  String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  Class
[] exclude() default {};
  String[] excludeName() default {};
}

Key supporting classes and methods are also presented:

Registrar class – implements ImportBeanDefinitionRegistrar and registers packages for auto‑configuration:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    @Override
    //metadata是我们注解所在的元信息
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        //将我们注解所在包下所有的组件进行注册
        register(registry, new PackageImport(metadata).getPackageName());
    }

    @Override
    public Set
determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new PackageImport(metadata));
    }
}

register method – adds package names to the AutoConfigurationPackages bean definition:

private static final String BEAN = AutoConfigurationPackages.class.getName();

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
    if (registry.containsBeanDefinition(BEAN)) {
        BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
        ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
        constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
    } else {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(BasePackages.class);
        beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(BEAN, beanDefinition);
    }
}

SelectImports method – loads auto‑configuration metadata and returns the classes to import:

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
        .loadMetadata(this.beanClassLoader);
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
        annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

isEnabled method – checks the override property to decide whether auto‑configuration should be applied:

protected boolean isEnabled(AnnotationMetadata metadata) {
    if (getClass() == AutoConfigurationImportSelector.class) {
        return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
    }
    return true;
}

loadMetadata method – reads META-INF/spring-autoconfigure-metadata.properties from the classpath:

protected static final String PATH = "META-INF/" + "spring-autoconfigure-metadata.properties";

public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
    return loadMetadata(classLoader, PATH);
}

static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
    try {
        Enumeration
urls = (classLoader != null) ? classLoader.getResources(path)
            : ClassLoader.getSystemResources(path);
        Properties properties = new Properties();
        while (urls.hasMoreElements()) {
            properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
        }
        return loadMetadata(properties);
    } catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
    }
}

static AutoConfigurationMetadata loadMetadata(Properties properties) {
    return new PropertiesAutoConfigurationMetadata(properties);
}

getAttributes method – extracts annotation attributes from metadata:

protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
    String name = getAnnotationClass().getName();
    AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
    Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
        + " annotated with " + ClassUtils.getShortName(name) + "?");
    return attributes;
}

getCandidateConfigurations method – loads candidate auto‑configuration class names from META-INF/spring.factories :

protected List
getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List
configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
        getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
        + "are using a custom packaging, make sure that file is correct.");
    return configurations;
}

protected Class
getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}

getAutoConfigurationEntry method – combines configurations, removes duplicates, applies exclusions, filters by conditions, and creates the final AutoConfigurationEntry :

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    List
configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set
exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = filter(configurations, autoConfigurationMetadata);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

In summary, @SpringBootApplication works by combining @SpringBootConfiguration (which marks the class as a configuration source), @EnableAutoConfiguration (which scans and loads auto‑configuration classes from the classpath), and @ComponentScan (which registers beans annotated with @Component and its stereotypes). This composition enables Spring Boot’s powerful automatic configuration capability.

backendJavaSpringBootannotationAutoConfigurationComponentScan
vivo Internet Technology
Written by

vivo Internet Technology

Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.

0 followers
Reader feedback

How this landed with the community

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