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.
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> @Valuecan 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 SpringApplicationRunListenerKey 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
Signed-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.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
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.
