Skip to content

Spring Boot 自动配置原理深度解析

面试官:说说 Spring Boot 的自动配置原理?

:Spring Boot 通过 @EnableAutoConfiguration 读取 classpath 下所有 META-INF/spring.factories(或 Spring Boot 3 的 .imports 文件)中注册的自动配置类,然后通过 @ConditionalOnXxx 条件注解过滤出当前环境需要的配置类并加载,实现”引入依赖即生效”的自动配置。

面试官:那自动配置类是如何被加载的?条件注解在什么时候判断?

这个问题考察的是你对SPI 机制条件注解执行时机的理解,只有掌握这些才能真正理解 Spring Boot 的”智能”自动配置。


链式追问一:@SpringBootApplication 组成

Section titled “链式追问一:@SpringBootApplication 组成”

Q1:@SpringBootApplication 注解的组成?必考

Section titled “Q1:@SpringBootApplication 注解的组成?”

回答要点

@SpringBootApplication 源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 1. 等价于 @Configuration
@EnableAutoConfiguration // 2. ★ 开启自动配置(核心)
@ComponentScan( // 3. 组件扫描
excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
}
)
public @interface SpringBootApplication {
// ...
}

三大核心注解

┌─────────────────────────────────────────────────────────────┐
│ @SpringBootConfiguration │
├─────────────────────────────────────────────────────────────┤
│ 等价于 @Configuration │
│ 标识主类是一个配置类,可以声明 @Bean 方法 │
│ │
│ 示例: │
│ @SpringBootApplication │
│ public class Application { │
│ @Bean │
│ public RestTemplate restTemplate() { │
│ return new RestTemplate(); │
│ } │
│ } │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ @EnableAutoConfiguration │
├─────────────────────────────────────────────────────────────┤
│ 开启自动配置,核心注解 │
│ │
│ @EnableAutoConfiguration 源码: │
│ @AutoConfigurationPackage │
│ @Import(AutoConfigurationImportSelector.class) │
│ │
│ 作用: │
│ 1. @AutoConfigurationPackage │
│ → 注册主类所在包为自动扫描包 │
│ → 保存到 BasePackages(供其他组件查询) │
│ │
│ 2. @Import(AutoConfigurationImportSelector.class) │
│ → 导入自动配置选择器 │
│ → 加载所有自动配置类 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ @ComponentScan │
├─────────────────────────────────────────────────────────────┤
│ 扫描当前包及子包的组件 │
│ 默认扫描:@Component、@Service、@Repository、@Controller │
│ │
│ 排除过滤器: │
│ • TypeExcludeFilter:排除指定类型的组件 │
│ • AutoConfigurationExcludeFilter:排除自动配置类 │
│ (避免被 @ComponentScan 扫描两次) │
└─────────────────────────────────────────────────────────────┘

本质一句话@SpringBootApplication 是三个注解的组合:@Configuration(配置类)+ @EnableAutoConfiguration(自动配置)+ @ComponentScan(组件扫描)。


Q2:@EnableAutoConfiguration 如何加载自动配置类?必考

Section titled “Q2:@EnableAutoConfiguration 如何加载自动配置类?”

自动配置加载流程

Spring Boot 启动流程中的自动配置:
1. @EnableAutoConfiguration 触发
2. @Import(AutoConfigurationImportSelector.class)
3. AutoConfigurationImportSelector.selectImports()
4. 读取 classpath 下所有 META-INF/spring.factories
5. 获取 key = EnableAutoConfiguration 的所有值(自动配置类列表)
6. 过滤 exclude 列表(通过 @SpringBootApplication.exclude 指定)
7. 去重、排序(@AutoConfigureBefore/After 控制顺序)
8. 条件注解过滤(@ConditionalOnXxx 判断是否生效)
9. 将满足条件的配置类注册为 BeanDefinition
10. 实例化自动配置类中的 Bean

Spring Boot 2.x vs 3.x 对比

Spring Boot 2.x(基于 spring.factories):
文件位置:
META-INF/spring.factories
文件格式:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
缺点:
• Properties 格式,需解析
• 所有配置类写在一行,难以维护
• 性能稍差(需要加载并解析文件)
Spring Boot 3.x(基于 imports 文件):
文件位置:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件格式:
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
优点:
• 每行一个类,简洁清晰
• 无需解析 Properties,性能更好
• 更符合 Java SPI 规范
兼容性:
• Spring Boot 3 仍支持 spring.factories(向后兼容)
• 推荐新项目使用 .imports 文件

源码示例

// AutoConfigurationImportSelector 核心源码(简化)
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 1. 获取所有自动配置类
AutoConfigurationEntry autoConfigurationEntry =
getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata metadata) {
// 1. 检查是否启用自动配置
if (!isEnabled(metadata)) {
return EMPTY_ENTRY;
}
// 2. 获取注解属性(exclude、excludeName)
AnnotationAttributes attributes = getAttributes(metadata);
// 3. ★ 读取 spring.factories 中的自动配置类
List<String> configurations = getCandidateConfigurations(metadata, attributes);
// 4. 去重
configurations = removeDuplicates(configurations);
// 5. 应用 exclude 列表
Set<String> exclusions = getExclusions(metadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 6. 过滤(条件注解)
configurations = getConfigurationClassFilter().filter(configurations);
// 7. 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
// 读取 spring.factories
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
return configurations;
}
}

Q1:@ConditionalOnXxx 条件注解是如何工作的?必考

Section titled “Q1:@ConditionalOnXxx 条件注解是如何工作的?”

条件注解分类

类条件注解:
@ConditionalOnClass → classpath 中存在指定类
@ConditionalOnMissingClass → classpath 中不存在指定类
Bean 条件注解:
@ConditionalOnBean → 容器中存在指定 Bean
@ConditionalOnMissingBean → 容器中不存在指定 Bean
属性条件注解:
@ConditionalOnProperty → 配置文件中存在且值匹配指定属性
应用类型条件注解:
@ConditionalOnWebApplication → 当前是 Web 应用
@ConditionalOnNotWebApplication → 当前不是 Web 应用
表达式条件注解:
@ConditionalOnExpression → SpEL 表达式为 true
资源条件注解:
@ConditionalOnResource → classpath 中存在指定资源文件
其他:
@ConditionalOnJava → JVM 版本满足条件
@ConditionalOnCloudPlatform → 运行在指定云平台

条件注解工作流程

自动配置类加载流程:
1. 读取候选配置类(spring.factories)
2. ConfigurationClassPostProcessor.processConfigBeanDefinitions()
3. ConfigurationClassParser.parse() 解析配置类
4. 检查类上的 @Conditional 注解
5. 调用 Condition.matches() 判断条件
6. 条件满足 → 继续解析
条件不满足 → 跳过该配置类
7. 解析配置类中的 @Bean 方法
8. 检查 @Bean 方法上的 @Conditional 注解
9. 条件满足 → 注册 BeanDefinition
条件不满足 → 跳过该 @Bean 方法

代码示例

@Configuration
@ConditionalOnClass(DataSource.class) // 1. classpath 有 DataSource 类
@ConditionalOnMissingBean(DataSourceInitializer.class) // 2. 容器中没有自定义 DataSourceInitializer
@EnableConfigurationProperties(DataSourceProperties.class) // 3. 绑定配置属性
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 4. 用户没有自定义时,才创建默认 Bean
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
@Bean
@ConditionalOnProperty(prefix = "spring.datasource", name = "continue-on-error",
havingValue = "true") // 5. 配置为 true 时才创建
public DataSourceInitializer dataSourceInitializer(DataSource dataSource,
DataSourceProperties properties) {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
initializer.setDatabasePopulator(properties.getDatabasePopulator());
return initializer;
}
}

条件注解实现原理

// @ConditionalOnClass 源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnClassCondition.class) // 指定 Condition 实现类
public @interface OnClassCondition {
Class<?>[] value() default {};
String[] name() default {};
}
// OnClassCondition 实现类
class OnClassCondition extends SpringBootCondition
implements ConfigurationCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
// 1. 获取注解中指定的类名
List<String> classNames = getClasses(metadata);
// 2. 检查 classpath 是否存在这些类
ClassLoader classLoader = context.getClassLoader();
for (String className : classNames) {
if (!ClassUtils.isPresent(className, classLoader)) {
// 类不存在,条件不满足
return ConditionOutcome.noMatch(
ConditionMessage.forCondition(ConditionalOnClass.class)
.didNotFind("required class", "required classes")
.items(Style.QUOTE, classNames));
}
}
// 3. 所有类都存在,条件满足
return ConditionOutcome.match(
ConditionMessage.forCondition(ConditionalOnClass.class)
.found("required class", "required classes")
.items(Style.QUOTE, classNames));
}
}

Q2:@ConditionalOnMissingBean 为什么能实现”允许用户覆盖”?高频

Section titled “Q2:@ConditionalOnMissingBean 为什么能实现”允许用户覆盖”?”

核心设计理念

自动配置的"约定大于配置":
1. 自动配置提供默认实现
2. 用户可以通过自定义 Bean 覆盖默认配置
3. @ConditionalOnMissingBean 检测容器中是否已有同类型 Bean
4. 如果用户已定义,自动配置的 Bean 不创建
5. 如果用户未定义,自动配置的 Bean 创建
好处:
• 零配置即可运行(使用默认配置)
• 需要定制时只需自定义 Bean(覆盖默认配置)
• 灵活且不侵入

代码示例

// RedisAutoConfiguration 源码(简化)
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate") // ★ 关键注解
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean // StringRedisTemplate 也可能被覆盖
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
// 用户自定义 RedisTemplate
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(
RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 自定义序列化
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisRedisSerializer<>(Object.class);
template.setDefaultSerializer(serializer);
return template;
}
}
// 结果:
// 自动配置的 redisTemplate 不创建(@ConditionalOnMissingBean 生效)
// 用户自定义的 redisTemplate 创建
// 实现了覆盖

对比表格

注解条件使用场景
@ConditionalOnBean容器中存在指定 Bean依赖其他 Bean 才能生效
@ConditionalOnMissingBean容器中不存在指定 Bean允许用户覆盖(最常用)
@ConditionalOnClassclasspath 存在指定类依赖第三方库才生效
@ConditionalOnMissingClassclasspath 不存在指定类不依赖第三方库时生效

Q1:如何自定义一个 Spring Boot Starter?实战

Section titled “Q1:如何自定义一个 Spring Boot Starter?”

Starter 开发规范

Starter 命名规范:
官方 Starter:spring-boot-starter-{name}
例:spring-boot-starter-web、spring-boot-starter-data-redis
第三方 Starter:{name}-spring-boot-starter
例:mybatis-spring-boot-starter、druid-spring-boot-starter
Starter 结构:
{name}-spring-boot-starter
├── pom.xml # 依赖管理
├── src/main/java
│ └── com.example
│ ├── autoconfigure # 自动配置类
│ │ ├── XxxAutoConfiguration.java
│ │ └── XxxProperties.java
│ └── starter # 功能实现(可选)
└── src/main/resources
└── META-INF
└── spring.factories # 注册自动配置类

实战示例:自定义 Redis Lock Starter

// 1. 创建 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project>
<groupId>com.example</groupId>
<artifactId>redis-lock-spring-boot-starter</artifactId>
<version>1.0.0</version>
<dependencies>
<!-- Spring Boot 自动配置依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- Redis 依赖(可选) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<optional>true</optional>
</dependency>
<!-- 配置处理器(生成配置元数据) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
// 2. 创建配置属性类
@ConfigurationProperties(prefix = "redis.lock")
public class RedisLockProperties {
private boolean enabled = true;
private long timeout = 30000; // 默认超时30秒
private String keyPrefix = "lock:";
// getters/setters
}
// 3. 创建核心功能类
public class RedisLockService {
private final RedisTemplate<String, String> redisTemplate;
private final RedisLockProperties properties;
public RedisLockService(RedisTemplate<String, String> redisTemplate,
RedisLockProperties properties) {
this.redisTemplate = redisTemplate;
this.properties = properties;
}
public boolean tryLock(String key, long timeout) {
String lockKey = properties.getKeyPrefix() + key;
String value = UUID.randomUUID().toString();
Boolean success = redisTemplate.opsForValue()
.setIfAbsent(lockKey, value, timeout, TimeUnit.MILLISECONDS);
return Boolean.TRUE.equals(success);
}
public void unlock(String key) {
String lockKey = properties.getKeyPrefix() + key;
redisTemplate.delete(lockKey);
}
}
// 4. 创建自动配置类
@Configuration
@ConditionalOnClass(RedisTemplate.class) // classpath 有 Redis
@ConditionalOnProperty(prefix = "redis.lock", name = "enabled",
havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(RedisLockProperties.class)
public class RedisLockAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 允许用户覆盖
public RedisLockService redisLockService(
RedisTemplate<String, String> redisTemplate,
RedisLockProperties properties) {
return new RedisLockService(redisTemplate, properties);
}
}
// 5. 注册自动配置类(META-INF/spring.factories)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfigure.RedisLockAutoConfiguration
// 6. 生成配置元数据(META-INF/spring-configuration-metadata.json)
{
"properties": [
{
"name": "redis.lock.enabled",
"type": "java.lang.Boolean",
"defaultValue": true,
"description": "Enable Redis lock."
},
{
"name": "redis.lock.timeout",
"type": "java.lang.Long",
"defaultValue": 30000,
"description": "Lock timeout in milliseconds."
},
{
"name": "redis.lock.key-prefix",
"type": "java.lang.String",
"defaultValue": "lock:",
"description": "Redis key prefix."
}
]
}

使用示例

// 引入依赖
<dependency>
<groupId>com.example</groupId>
<artifactId>redis-lock-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
// 配置文件(application.yml)
redis:
lock:
enabled: true
timeout: 60000 # 60秒超时
key-prefix: "myapp:lock:"
// 使用
@Service
public class OrderService {
@Autowired
private RedisLockService lockService;
public void createOrder(String orderId) {
String lockKey = "order:" + orderId;
if (lockService.tryLock(lockKey, 60000)) {
try {
// 业务逻辑
} finally {
lockService.unlock(lockKey);
}
} else {
throw new RuntimeException("获取锁失败");
}
}
}

链式追问四:Spring Boot 启动流程

Section titled “链式追问四:Spring Boot 启动流程”

Q1:Spring Boot 的启动流程是怎样的?必考

Section titled “Q1:Spring Boot 的启动流程是怎样的?”

完整启动流程

SpringApplication.run(Application.class, args)
┌─────────────────────────────────────────────────────────────┐
│ 阶段1:创建 SpringApplication 对象 │
├─────────────────────────────────────────────────────────────┤
│ new SpringApplication(primarySource) │
│ ↓ │
│ 1. 推断应用类型(NONE / SERVLET / REACTIVE) │
│ • 检查 classpath 是否有 Servlet 类 │
│ • 检查 classpath 是否有 Reactive 类 │
│ │
│ 2. 加载 ApplicationContextInitializer(spring.factories) │
│ • 用于在 ApplicationContext 刷新前进行初始化 │
│ • 例:ContextIdApplicationContextInitializer │
│ │
│ 3. 加载 ApplicationListener(spring.factories) │
│ • 监听 SpringApplication 事件 │
│ • 例:LoggingApplicationListener、ConfigFileAppList │
│ │
│ 4. 推断主类(main 方法所在类) │
│ • 通过异常堆栈找到 main 方法 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 阶段2:执行 run() 方法 │
├─────────────────────────────────────────────────────────────┤
│ 1. StopWatch 计时开始 │
│ │
│ 2. 创建并启动 SpringApplicationRunListeners │
│ • listeners.starting() │
│ • 发布 ApplicationStartingEvent │
│ │
│ 3. 准备 Environment(环境变量、配置文件) │
│ • 创建 StandardServletEnvironment │
│ • 加载 application.yml / application.properties │
│ • listeners.environmentPrepared() │
│ • 发布 ApplicationEnvironmentPreparedEvent │
│ │
│ 4. 打印 Banner(彩色 Spring 字样) │
│ • 检查 spring.main.banner-mode 配置 │
│ │
│ 5. 创建 ApplicationContext │
│ • SERVLET → AnnotationConfigServletWebServerAppContext │
│ • REACTIVE → AnnotationConfigReactiveWebServerAppCtx │
│ • NONE → AnnotationConfigApplicationContext │
│ │
│ 6. prepareContext() │
│ • 应用 ApplicationContextInitializer │
│ • listeners.contextPrepared() │
│ • 加载主类 BeanDefinition │
│ • listeners.contextLoaded() │
│ • 发布 ApplicationContextInitializedEvent │
│ │
│ 7. ★ refreshContext()(核心) │
│ • 调用 AbstractApplicationContext.refresh() │
│ • 扫描 + 解析 + 注册所有 BeanDefinition │
│ • 加载自动配置类(此时 @ConditionalOnXxx 判断) │
│ • 实例化所有非懒加载单例 Bean │
│ • 初始化内嵌 Web 服务器(Tomcat) │
│ • DispatcherServlet 等 MVC 组件初始化 │
│ │
│ 8. afterRefresh()(空实现,扩展点) │
│ │
│ 9. StopWatch 计时结束,打印启动耗时 │
│ • listeners.started() │
│ • 发布 ApplicationStartedEvent │
│ │
│ 10. callRunners() │
│ • 执行 ApplicationRunner / CommandLineRunner │
│ • 用于启动后执行自定义逻辑 │
│ │
│ 11. listeners.running() │
│ • 发布 ApplicationReadyEvent │
│ • 应用启动完成 │
└─────────────────────────────────────────────────────────────┘

关键扩展点

// 1. ApplicationContextInitializer
public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext context) {
// 在 ApplicationContext 刷新前执行
System.out.println("初始化 ApplicationContext");
}
}
// 注册:META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=\
com.example.MyInitializer
// 2. ApplicationRunner
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
// 在应用启动后执行
System.out.println("应用启动完成,执行初始化逻辑");
}
}
// 3. CommandLineRunner
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 在应用启动后执行(与 ApplicationRunner 类似)
System.out.println("命令行参数: " + Arrays.toString(args));
}
}

Q2:内嵌 Tomcat 是如何启动的?高频

Section titled “Q2:内嵌 Tomcat 是如何启动的?”

Tomcat 启动流程

refreshContext() → AbstractApplicationContext.refresh()
onRefresh()(ServletWebServerApplicationContext)
createWebServer()
┌─────────────────────────────────────────────────────────────┐
│ 1. 获取 ServletWebServerFactory │
├─────────────────────────────────────────────────────────────┤
│ • 从容器获取 ServletWebServerFactory Bean │
│ • TomcatServletWebServerFactory(默认) │
│ • JettyServletWebServerFactory │
│ • UndertowServletWebServerFactory │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 2. 创建 WebServer │
├─────────────────────────────────────────────────────────────┤
│ factory.getWebServer(servletContext) │
│ ↓ │
│ • 创建 Tomcat 实例 │
│ • 设置端口(server.port,默认8080) │
│ • 配置连接器(Connector) │
│ • 配置引擎(Engine)、主机(Host)、上下文(Context) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 3. 注册 DispatcherServlet │
├─────────────────────────────────────────────────────────────┤
│ • ServletRegistrationBean<DispatcherServlet> │
│ • 映射到 "/"(处理所有请求) │
│ • 设置加载顺序(loadOnStartup = 1) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 4. 启动 Tomcat │
├─────────────────────────────────────────────────────────────┤
│ tomcat.start() │
│ ↓ │
│ • 初始化连接器(绑定端口) │
│ • 启动内部组件 │
│ • 触发 LifecycleListener │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 5. 发布事件 │
├─────────────────────────────────────────────────────────────┤
│ ServletWebServerInitializedEvent │
│ • 包含 WebServer 和 ApplicationContext 信息 │
│ • 通知应用 Web 服务器已启动 │
└─────────────────────────────────────────────────────────────┘

性能数据

Spring Boot 2.7 启动时间(MacBook Pro M1):
空项目: ~1.2s
引入 Web: ~2.1s
引入 JPA: ~2.8s
引入 Redis: ~2.5s
Tomcat 启动时间:
创建 Tomcat: ~200ms
启动连接器: ~100ms
总计: ~300ms
优化建议:
1. 延迟初始化(spring.main.lazy-initialization=true)
→ 启动时间减少 30-50%
→ 首次请求延迟增加
2. 禁用不必要的自动配置
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
3. 使用 Spring Boot 3.x(启动性能优化)
→ 比 Spring Boot 2.x 快 10-20%

Q:Spring Boot 自动配置原理?

@EnableAutoConfiguration 通过 AutoConfigurationImportSelector 读取 META-INF/spring.factories(或 Spring Boot 3 的 .imports 文件)中注册的自动配置类,通过 @ConditionalOnXxx 条件注解过滤出当前环境需要的配置类并加载,实现”引入依赖即生效”。

Q:@ConditionalOnMissingBean 的作用?

容器中不存在指定 Bean 时配置才生效,这是”允许用户覆盖”的核心机制。自动配置的 Bean 声明上都加了这个注解,用户自定义同类型 Bean 后,自动配置的 Bean 不会创建,实现用户自定义覆盖默认行为。

Q:如何自定义 Starter?

  1. 创建 Maven 模块(命名:{name}-spring-boot-starter);2. 在 META-INF/spring.factories 配置 EnableAutoConfiguration 指向自动配置类;3. 自动配置类使用 @ConditionalOnXxx 条件注解;4. 使用 @ConfigurationProperties 绑定配置;5. 使用 @ConditionalOnMissingBean 允许用户覆盖。

Q:Spring Boot 启动流程?

核心在 SpringApplication.run():准备环境(加载配置文件)→ 创建 ApplicationContext → prepareContext(应用 Initializer、加载主类 BeanDefinition)→ refreshContext(扫描+实例化所有 Bean、启动内嵌 Tomcat)→ 执行 ApplicationRunner/CommandLineRunner。

Q:Spring Boot 2.x 和 3.x 自动配置的区别?

Spring Boot 2.x 基于 META-INF/spring.factories(Properties 格式);Spring Boot 3.x 基于 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(每行一个类,性能更好)。Spring Boot 3 仍兼容 spring.factories。