Understanding Spring Boot Auto‑Configuration and Common Annotations

This article explains how Spring Boot’s auto‑configuration works, introduces the most frequently used annotations such as @Value, @ConfigurationProperties, @Import and @Conditional, and provides practical code examples to illustrate the underlying mechanisms and startup process of a Spring Boot application.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Understanding Spring Boot Auto‑Configuration and Common Annotations

Preface

Before Spring Boot became popular, many projects used the SSM architecture, which required a lot of XML configuration and caused many pain points. Spring Boot introduced zero‑configuration, making development much smoother thanks to its auto‑configuration mechanism.

Quick Overview of Common Spring Boot Annotations

Understanding the following annotations helps you read the source code more easily.

Composite Annotation

When several annotations are often used together on the same class, they can be combined into a single meta‑annotation.

Meta‑annotation: an annotation that can be placed on other annotations.

Composite annotation: the annotation that is itself annotated by a meta‑annotation.

@Value

The @Value annotation is provided by Spring (not Spring Boot) and lives in spring-beans.jar. It works like the value attribute in a traditional XML configuration file.

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
    /**
     * The actual value expression, e.g. #{systemProperties.myProp}.
     */
    String value();
}

Example usage:

@Component
public class Person {
    @Value("i am name")
    private String name;
}

The equivalent XML configuration would be:

<bean class="Person">
    <property name="name" value="i am name"/>
</bean>
@Value

can resolve values from literals, environment variables (${key}), global configuration files (${key}), or SpEL (#{...}).

Drawbacks of using @Value for many properties:

Configuration properties are not unified and lack structure.

Each property requires explicit mapping, leading to repetitive code.

Configuration becomes scattered throughout the project.

@ConfigurationProperties

This annotation is provided by Spring Boot (in spring-boot.jar) under the package org.springframework.boot.context.properties. It binds a group of related configuration items to a POJO.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationProperties {
    @AliasFor("prefix")
    String value() default "";
    @AliasFor("value")
    String prefix() default "";
    // ... other attributes ...
}

When many configuration items (e.g., account, password, url) need to be accessed, using @ConfigurationProperties is far more convenient than multiple @Value annotations.

Example:

# application.properties
pay.account=java后端技术全栈
pay.password=tj20120622
pay.url=http://woaijava.cc
@Component
@ConfigurationProperties(prefix = "pay")
public class PayInfo {
    private String account;
    private Integer password;
    private String url;
    // getters and setters omitted for brevity
}

After defining the class, Spring Boot will automatically bind the properties prefixed with pay to the fields of PayInfo, allowing you to inject PayInfo wherever needed.

@Import (Spring provided)

The @Import annotation imports ordinary Java classes and registers them as beans, enabling the composition of multiple configuration classes into a larger one.

Before Spring 4.2, only configuration classes could be imported.

Since Spring 4.2, any regular Java class can be imported and turned into a bean.

Three usage patterns:

Directly import a regular Java class.

Combine with a custom ImportSelector.

Combine with an ImportBeanDefinitionRegistrar.

1. Direct import

public class Circle {
    public void sayHi() {
        System.out.println("Circle sayHi()");
    }
}
@Import({Circle.class})
@Configuration
public class MainConfig {
}

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        Circle circle = context.getBean(Circle.class);
        circle.sayHi();
    }
}

Output: Circle sayHi() 2. ImportSelector

public class Triangle {
    public void sayHi() {
        System.out.println("Triangle sayHi()");
    }
}
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        return new String[]{"annotation.importannotation.waytwo.Triangle"};
    }
}
@Import({Circle.class, MyImportSelector.class})
@Configuration
public class MainConfigTwo {
}

public class MainTwo {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigTwo.class);
        Circle circle = context.getBean(Circle.class);
        Triangle triangle = context.getBean(Triangle.class);
        circle.sayHi();
        triangle.sayHi();
    }
}

Output: Circle sayHi() and Triangle sayHi() 3. ImportBeanDefinitionRegistrar

public class Rectangle {
    public void sayHi() {
        System.out.println("Rectangle sayHi()");
    }
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(Rectangle.class);
        registry.registerBeanDefinition("rectangle", beanDefinition);
    }
}
@Import({Circle.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
@Configuration
public class MainConfigThree {
}

public class MainThree {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigThree.class);
        Circle circle = context.getBean(Circle.class);
        Triangle triangle = context.getBean(Triangle.class);
        Rectangle rectangle = context.getBean(Rectangle.class);
        circle.sayHi();
        triangle.sayHi();
        rectangle.sayHi();
    }
}

Output: Circle sayHi(), Triangle sayHi(),

Rectangle sayHi()

@Conditional (Spring provided)

The @Conditional annotation activates a configuration only when a specified condition is met.

public class ConditionBean {
    public void sayHi() {
        System.out.println("ConditionBean sayHi()");
    }
}
public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true; // change to false to disable the configuration
    }
}
@Configuration
@Conditional(MyCondition.class)
public class ConditionConfig {
    @Bean
    public ConditionBean conditionBean() {
        return new ConditionBean();
    }
}

public class ConditionMain {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(ConditionConfig.class);
        ConditionBean bean = ctx.getBean(ConditionBean.class);
        bean.sayHi();
    }
}

If matches() returns false, the bean will not be created.

Spring Boot Startup Process

The startup sequence repeatedly invokes four key interfaces:

ApplicationContextInitializer
ApplicationRunner
CommandLineRunner
SpringApplicationRunListener

Key steps:

Create a SpringApplication instance.

Execute run(), which prepares the environment, prints the banner, creates the appropriate ApplicationContext, registers listeners, refreshes the context, and finally invokes runners.

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    this.sources = new LinkedHashSet();
    this.bannerMode = Mode.CONSOLE;
    this.logStartupInfo = true;
    // ... other default settings ...
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting();
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
        Banner printedBanner = this.printBanner(environment);
        context = this.createApplicationContext();
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        this.refreshContext(context);
        this.afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(this.getApplicationLog(), stopWatch);
        }
        listeners.started(context);
        this.callRunners(context, applicationArguments);
    } catch (Throwable ex) {
        this.handleRunFailure(context, ex, null, listeners);
        throw new IllegalStateException(ex);
    }
    listeners.running(context);
    return context;
}

Spring Boot Auto‑Configuration Principle

@SpringBootApplication

This meta‑annotation combines @SpringBootConfiguration, @EnableAutoConfiguration, and @ComponentScan. It marks the main configuration class and triggers component scanning and auto‑configuration.

@EnableAutoConfiguration

Imports a set of auto‑configuration classes via AutoConfigurationImportSelector, which reads META‑INF/spring.factories to obtain the list of candidates.

@AutoConfigurationPackage

Registers a Registrar that adds the package of the main configuration class (and its sub‑packages) to the component scan.

Auto‑configuration import selector

The selector’s selectImports() method calls getAutoConfigurationEntry(), which loads the spring.factories file, extracts the value of the EnableAutoConfiguration key, and returns the fully‑qualified class names of all auto‑configuration candidates.

Example: HttpEncodingAutoConfiguration

This class is annotated with:

@Configuration
@ConditionalOnWebApplication(type = SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(HttpProperties.class)

When the conditions are satisfied, Spring Boot creates beans based on the values bound to HttpProperties (a @ConfigurationProperties class).

HttpProperties

@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {
    // fields representing configuration items
}

Properties defined in application.properties with the spring.http prefix are automatically bound to this POJO.

Summary

Spring Boot loads many auto‑configuration classes at startup.

Check whether the functionality you need already has a default auto‑configuration class.

If it does, you can rely on the beans it provides without writing additional configuration.

Auto‑configuration classes obtain configuration values from corresponding *Properties classes, which are bound to the external configuration files.

All auto‑configuration candidates are listed in META‑INF/spring.factories, making it easy for third‑party libraries to contribute starters.

References: kil51.cn/JTg9D, blog.51cto.com/4247649/2118354, www.cnblogs.com/duanxz/p/3787757.html, www.jianshu.com/p/e22b9fef311c, blog.csdn.net/qq_26525215/article/details/53523970, http://www.woaijava.cc

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 Bootannotationsauto-configuration
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

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.