Spring Boot 自动配置源码拆解:AutoConfigurationImportSelector 到底做了什么
引言
Spring Boot 的"魔法"从哪来?为什么加一个依赖,DataSource 就自动配置好了?为什么 @SpringBootApplication 一个注解就能启动整个应用?
答案藏在 AutoConfigurationImportSelector 这个类里。
本文从 @SpringBootApplication 注解出发,逐层深入源码,拆解自动配置的完整执行链路。读完后,你将彻底理解 Spring Boot 自动配置的工作原理,并能自己写一个 starter。
本文基于 Spring Boot 3.3.x / Spring Framework 6.1.x 源码分析。
一、从 @SpringBootApplication 开始
1.1 注解的"套娃"结构
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
点开 @SpringBootApplication:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // ← 就是 @Configuration
@EnableAutoConfiguration // ← 自动配置的入口
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {
// 排除指定的自动配置类
Class<?>[] exclude() default {};
// 排除指定的自动配置类名
String[] excludeName() default {};
String[] scanBasePackages() default {};
Class<?>[] scanBasePackageClasses() default {};
// ...
}
三个核心注解:
| 注解 | 作用 |
|---|---|
@SpringBootConfiguration | 标记配置类(本质是 @Configuration) |
@EnableAutoConfiguration | 自动配置入口,本文重点 |
@ComponentScan | 包扫描,扫描 @Component 等注解 |
1.2 @EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // ← 注册包路径
@Import(AutoConfigurationImportSelector.class) // ← 关键!导入 Selector
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
关键在 @Import(AutoConfigurationImportSelector.class)——这才是自动配置的真正入口。
@Import 的三种用法:
- 导入普通类(直接注册为 Bean)
- 导入
@Configuration类 - 导入
ImportSelector或ImportBeanDefinitionRegistrar
AutoConfigurationImportSelector 实现了 ImportSelector 接口,Spring 会调用它的 selectImports() 方法,返回的类名数组全部被注册为配置类。
二、AutoConfigurationImportSelector.selectImports()
2.1 调用链路
SpringApplication.run()
→ refreshContext()
→ invokeBeanFactoryPostProcessors()
→ ConfigurationClassPostProcessor.processConfigBeanDefinitions()
→ ConfigurationClassParser.parse()
→ processImports() ← 处理 @Import 注解
→ AutoConfigurationImportSelector.selectImports() ← 入口
→ getAutoConfigurationEntry()
→ getCandidateConfigurations() ← 加载候选配置
→ removeDuplicates() ← 去重
→ removeExclusions() ← 排除
→ filter() ← 条件过滤
2.2 selectImports 源码
public class AutoConfigurationImportSelector implements DeferredImportSelector,
BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 检查是否开启了自动配置(默认开启)
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 加载自动配置条目(核心方法)
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected boolean isEnabled(AnnotationMetadata metadata) {
// 读取 spring.boot.enableautoconfiguration 属性,默认 true
if (getClass() == AutoConfigurationImportSelector.class) {
return getEnvironment().getProperty(
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
}
2.3 getAutoConfigurationEntry 源码
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取 @EnableAutoConfiguration 的属性(exclude, excludeName)
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// ① 加载所有候选配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// ② 去重
configurations = removeDuplicates(configurations);
// ③ 应用排除(@SpringBootApplication.exclude 属性)
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
// ④ 触发监听器
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
四个核心步骤:
① 加载候选 → ② 去重 → ③ 排除 → ④ 过滤
三、加载候选配置:getCandidateConfigurations()
3.1 Spring Boot 2.7+ 的变化
Spring Boot 2.7 之前,用 SpringFactoriesLoader 加载 spring.factories:
// 老方式(2.7 之前)
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
EnableAutoConfiguration.class, getBeanClassLoader());
读取 META-INF/spring.factories 文件:
# spring-boot-autoconfigure/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
# ... 几百个自动配置类
Spring Boot 2.7+,改用 ImportCandidates 加载新文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
// 新方式(2.7+)
List<String> configurations = ImportCandidates.load(
AutoConfiguration.class, getBeanClassLoader()).getCandidates();
读取新文件(每行一个类名,更简洁):
# spring-boot-autoconfigure/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
# ...
3.2 为什么要换
| 维度 | spring.factories | AutoConfiguration.imports |
|---|---|---|
| 文件格式 | key=value,一个 key 挂多个 value | 每行一个类名 |
| 文件大小 | spring.factories 越来越臃肿 | 专用文件,职责单一 |
| 加载效率 | SpringFactoriesLoader 缓存所有 key | ImportCandidates 只加载目标 |
| 可读性 | 差(长行换行混乱) | 好(一行一个) |
3.3 源码(2.7+ 版本)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = ImportCandidates.load(
AutoConfiguration.class, getBeanClassLoader()).getCandidates();
// 兼容老方式(spring.factories 仍然支持,但会告警)
if (configurations.isEmpty()) {
configurations = SpringFactoriesLoader.loadFactoryNames(
EnableAutoConfiguration.class, getBeanClassLoader());
}
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring/...AutoConfiguration.imports");
return configurations;
}
3.4 验证:查看 Spring Boot 自带多少自动配置类
# 解压 spring-boot-autoconfigure jar
jar tf spring-boot-autoconfigure-3.3.2.jar | grep AutoConfiguration.imports
# 查看内容
unzip -p spring-boot-autoconfigure-3.3.2.jar \
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | wc -l
# 输出:147(Spring Boot 3.3.2 有 147 个自动配置类)
四、条件过滤:ConfigurationClassFilter
加载到的 147 个候选配置类,不是全部生效的。Spring 会根据条件注解过滤。
4.1 过滤流程
// getAutoConfigurationEntry() 中的过滤调用
configurations = getConfigurationClassFilter().filter(configurations);
// ConfigurationClassFilter.filter()
List<String> filter(List<String> configurations) {
long startTime = System.currentTimeMillis();
// 用 AutoConfigurationImportFilter 过滤
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skipped = new boolean[candidates.length];
// 遍历所有 Filter(OnClassCondition, OnBeanCondition, OnWebApplicationCondition)
for (AutoConfigurationImportFilter filter : this.filters) {
boolean[] match = filter.match(candidates, getAutoConfigurationMetadata());
for (int i = 0; i < candidates.length; i++) {
if (!match[i]) {
skipped[i] = true;
}
}
}
// 收集未被跳过的
List<String> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skipped[i]) {
result.add(candidates[i]);
}
}
return result;
}
4.2 核心条件注解
| 注解 | 条件 | 示例 |
|---|---|---|
@ConditionalOnClass | classpath 存在指定类 | 有 DataSource 才配置数据源 |
@ConditionalOnMissingClass | classpath 不存在指定类 | - |
@ConditionalOnBean | 容器中存在指定 Bean | 有 DataSource 才配置 JdbcTemplate |
@ConditionalOnMissingBean | 容器中不存在指定 Bean | 用户没自定义才用默认的 |
@ConditionalOnProperty | 配置属性满足条件 | spring.datasource.url 存在才配置 |
@ConditionalOnWebApplication | 是 Web 应用 | 是 Servlet 应用才配置 MVC |
@ConditionalOnNotWebApplication | 不是 Web 应用 | - |
@ConditionalOnResource | 资源文件存在 | classpath:db/migration 存在才配置 Flyway |
4.3 源码示例:DataSourceAutoConfiguration
@AutoConfiguration(before = SqlInitializationAutoConfiguration.class)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import(DataSourcePoolMetadataProvidersConfiguration.class)
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
}
// ...
}
解读:
| 注解 | 含义 |
|---|---|
@ConditionalOnClass({DataSource.class, ...}) | classpath 有 JDBC API 才生效 |
@ConditionalOnMissingBean(type="io.r2dbc...") | 没用 R2DBC(响应式)才生效 |
@ConditionalOnMissingBean({DataSource.class, ...}) | 用户没自定义 DataSource 才用默认的 |
4.4 @ConditionalOnBean 的"坑"
@ConditionalOnBean 有一个经典坑:
@Configuration
public class MyConfig {
@Bean
public DataSource myDataSource() {
return new HikariDataSource();
}
}
@Configuration
@ConditionalOnBean(DataSource.class) // ← 可能不生效!
public class JdbcConfig {
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
原因:@ConditionalOnBean 在配置类解析阶段判断,此时 MyConfig 可能还没被处理,容器里还没有 DataSource。
解决:
- 用
@AutoConfigureAfter指定顺序:
@AutoConfigureAfter(MyConfig.class)
@Configuration
@ConditionalOnBean(DataSource.class)
public class JdbcConfig { ... }
- 或用
@ConditionalOnClass代替(判断类而非 Bean) - 官方建议:自定义的自动配置类尽量用
@ConditionalOnClass和@ConditionalOnMissingBean,慎用@ConditionalOnBean
五、排除机制
5.1 三种排除方式
// 方式一:@SpringBootApplication.exclude
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApplication { ... }
// 方式二:@SpringBootApplication.excludeName
@SpringBootApplication(excludeName = {
"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"
})
public class MyApplication { ... }
// 方式三:配置文件
# application.yml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
5.2 排除源码
protected Set<String> getExclusions(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
// ① 从 @EnableAutoConfiguration.exclude 属性获取
excluded.addAll(asList(attributes, "exclude"));
// ② 从 @EnableAutoConfiguration.excludeName 属性获取
excluded.addAll(asList(attributes, "excludeName"));
// ③ 从配置文件 spring.autoconfigure.exclude 获取
excluded.addAll(getExcludeConfigurationsProperty());
return excluded;
}
5.3 排除的典型场景
// 场景:不用 Spring Boot 默认的数据源,用多数据源
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApplication { ... }
// 场景:不用 JPA,用 MyBatis
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class MyApplication { ... }
六、自动配置的执行顺序
6.1 顺序控制注解
| 注解 | 作用 |
|---|---|
@AutoConfigureBefore(X.class) | 在 X 之前配置 |
@AutoConfigureAfter(X.class) | 在 X 之后配置 |
@AutoConfigureOrder(1) | 数字越小优先级越高 |
6.2 示例
@AutoConfiguration(after = DataSourceAutoConfiguration.class)
@ConditionalOnClass({DataSource.class, JdbcTemplate.class})
@ConditionalOnBean(DataSource.class)
public class JdbcTemplateAutoConfiguration {
@Bean
@ConditionalOnMissingBean(JdbcTemplate.class)
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
JdbcTemplateAutoConfiguration 必须在 DataSourceAutoConfiguration 之后,否则 DataSource 还没创建。
6.3 排序源码
// AutoConfigurationSorter
public List<String> getByInDependencyOrder(Collection<String> classNames) {
// 1. 构建依赖图
Map<String, AutoConfigurationClass> classes = new HashMap<>();
for (String className : classNames) {
classes.put(className, new AutoConfigurationClass(className, ...));
}
// 2. 拓扑排序
List<String> ordered = new ArrayList<>();
Set<String> visited = new HashSet<>();
for (String className : classNames) {
visit(className, classes, visited, ordered);
}
return ordered;
}
七、Debug:看自动配置报告
7.1 开启 debug 模式
# application.yml
debug: true
或启动参数:
java -jar myapp.jar --debug
7.2 ConditionEvaluationReport
启动日志会输出自动配置报告:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:(生效的自动配置)
-----------------
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required classes 'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType' (OnClassCondition)
- @ConditionalOnMissingBean (types: io.r2dbc.spi.ConnectionFactory; SearchStrategy: all) did not find any beans (OnBeanCondition)
DataSourceConfiguration.Hikari matched:
- @ConditionalOnClass found required class 'com.zaxxer.hikari.HikariDataSource' (OnClassCondition)
- @ConditionalOnProperty (spring.datasource.type=com.zaxxer.hikari.HikariDataSource) matched (OnPropertyCondition)
Negative matches:(未生效的自动配置)
-----------------
DataSourceConfiguration.Tomcat did NOT match:
- @ConditionalOnClass did not find required class 'org.apache.tomcat.jdbc.pool.DataSource' (OnClassCondition)
RedisAutoConfiguration did NOT match:
- @ConditionalOnClass did not find required class 'org.springframework.data.redis.core.RedisOperations' (OnClassCondition)
Unconditional classes:(无条件限制,始终生效)
----------------------
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
Exclusions:(被排除的)
----------
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
7.3 用 Actuator 查看生效的配置
management:
endpoints:
web:
exposure:
include: conditions
访问 http://localhost:8080/actuator/conditions,返回 JSON 格式的报告。
八、实战:手写一个 Starter
8.1 需求
写一个 hello-spring-boot-starter,引入后自动配置一个 HelloService,支持配置自定义问候语。
8.2 项目结构
hello-spring-boot-starter/
├── pom.xml
└── src/main/
├── java/com/example/hello/
│ ├── HelloAutoConfiguration.java # 自动配置类
│ ├── HelloProperties.java # 配置属性绑定
│ └── HelloService.java # 核心服务
└── resources/
└── META-INF/
├── spring/
│ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
└── additional-spring-configuration-metadata.json
8.3 核心代码
HelloProperties.java:
package com.example.hello;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
private String prefix = "Hello"; // 问候前缀
private String suffix = "!"; // 问候后缀
private boolean enabled = true; // 是否启用
// getter/setter 省略
}
HelloService.java:
package com.example.hello;
public class HelloService {
private final HelloProperties properties;
public HelloService(HelloProperties properties) {
this.properties = properties;
}
public String sayHello(String name) {
if (!properties.isEnabled()) {
return "Hello feature is disabled";
}
return properties.getPrefix() + ", " + name + properties.getSuffix();
}
}
HelloAutoConfiguration.java:
package com.example.hello;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@AutoConfiguration
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(
prefix = "hello",
name = "enabled",
havingValue = "true",
matchIfMissing = true // 不配置时默认启用
)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 用户没自定义才用默认的
public HelloService helloService(HelloProperties properties) {
return new HelloService(properties);
}
}
注册自动配置类(Spring Boot 2.7+ 方式):
# src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.hello.HelloAutoConfiguration
8.4 使用
在业务项目中引入依赖:
<dependency>
<groupId>com.example</groupId>
<artifactId>hello-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
配置:
hello:
prefix: 你好
suffix: ~
enabled: true
使用:
@RestController
public class DemoController {
@Autowired
private HelloService helloService;
@GetMapping("/hello")
public String hello(@RequestParam String name) {
return helloService.sayHello(name); // 输出:你好, 张三~
}
}
8.5 自定义覆盖
用户可以自定义 HelloService 覆盖默认的:
@Configuration
public class MyConfig {
@Bean
public HelloService helloService(HelloProperties properties) {
// 自定义实现,默认的不会创建(因为 @ConditionalOnMissingBean)
return new MyCustomHelloService(properties);
}
}
这就是 @ConditionalOnMissingBean 的核心价值:默认配置可被用户覆盖。
九、总结
自动配置完整流程
@SpringBootApplication
→ @EnableAutoConfiguration
→ @Import(AutoConfigurationImportSelector.class)
→ selectImports()
→ getAutoConfigurationEntry()
├── ① getCandidateConfigurations() 加载 147 个候选
│ └── ImportCandidates.load() 读取 .imports 文件
├── ② removeDuplicates() 去重
├── ③ getExclusions() + removeAll() 排除
│ ├── @SpringBootApplication.exclude
│ ├── @SpringBootApplication.excludeName
│ └── spring.autoconfigure.exclude 配置项
└── ④ ConfigurationClassFilter.filter() 条件过滤
├── @ConditionalOnClass 类是否存在
├── @ConditionalOnBean Bean 是否存在
├── @ConditionalOnProperty 属性是否满足
└── @ConditionalOnWebApplication 是否 Web 应用
↓
最终生效的配置类(通常 20-30 个)
↓
解析为 BeanDefinition 注册到容器
↓
实例化 Bean
核心设计思想
| 设计 | 作用 |
|---|---|
| 约定优于配置 | 加依赖即生效,不用手动配置 |
| 条件化配置 | 根据环境自动适配,按需生效 |
| 可覆盖 | @ConditionalOnMissingBean 让用户能覆盖默认 |
| 可排除 | exclude 机制让用户能禁用不想要的 |
| 可排序 | @AutoConfigureAfter 保证依赖顺序 |
面试常考
| 问题 | 答案要点 |
|---|---|
| Spring Boot 自动配置原理? | @Import(Selector) → selectImports() → 加载 .imports → 条件过滤 |
| spring.factories 和 .imports 的区别? | 2.7+ 改用 .imports 文件,格式更简洁,职责单一 |
@ConditionalOnBean 的坑? | 解析阶段判断,可能 Bean 还没创建,用 @AutoConfigureAfter |
| 如何禁用某个自动配置? | exclude 属性 或 spring.autoconfigure.exclude 配置 |
| 如何查看生效了哪些自动配置? | --debug 启动 或 /actuator/conditions |
互动话题:你写过自定义 Starter 吗?遇到最大的坑是什么?欢迎留言讨论!
参考资料
标题:Spring Boot 自动配置源码拆解:AutoConfigurationImportSelector 到底做了什么
作者:jiangyi
地址:http://jiangyi.space/articles/2026/08/04/1785576729637.html
公众号:服务端技术精选
- 引言
- 一、从 @SpringBootApplication 开始
- 1.1 注解的"套娃"结构
- 1.2 @EnableAutoConfiguration
- 二、AutoConfigurationImportSelector.selectImports()
- 2.1 调用链路
- 2.2 selectImports 源码
- 2.3 getAutoConfigurationEntry 源码
- 三、加载候选配置:getCandidateConfigurations()
- 3.1 Spring Boot 2.7+ 的变化
- 3.2 为什么要换
- 3.3 源码(2.7+ 版本)
- 3.4 验证:查看 Spring Boot 自带多少自动配置类
- 四、条件过滤:ConfigurationClassFilter
- 4.1 过滤流程
- 4.2 核心条件注解
- 4.3 源码示例:DataSourceAutoConfiguration
- 4.4 @ConditionalOnBean 的"坑"
- 五、排除机制
- 5.1 三种排除方式
- 5.2 排除源码
- 5.3 排除的典型场景
- 六、自动配置的执行顺序
- 6.1 顺序控制注解
- 6.2 示例
- 6.3 排序源码
- 七、Debug:看自动配置报告
- 7.1 开启 debug 模式
- 7.2 ConditionEvaluationReport
- 7.3 用 Actuator 查看生效的配置
- 八、实战:手写一个 Starter
- 8.1 需求
- 8.2 项目结构
- 8.3 核心代码
- 8.4 使用
- 8.5 自定义覆盖
- 九、总结
- 自动配置完整流程
- 核心设计思想
- 面试常考
- 参考资料
评论