@SpringBootApplication 源码分析
概述
@SpringBootApplication 是 Spring Boot 应用最核心的注解,通常标注在启动类上。它是一个 组合注解,聚合了三个关键注解的功能。本文将深入源码层面,逐层拆解其组合结构、加载机制和自动配置全流程。
本文基于 Spring Boot 3.x 源码分析,部分内容会对比 Spring Boot 2.x 的差异。
1. @SpringBootApplication 组合注解结构
1.1 注解源码
@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 {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
Class<? extends BeanNameGenerator> nameGenerator()
default BeanNameGenerator.class;
@AliasFor(annotation = ComponentScan.class, attribute = "lazyInit")
boolean lazyInit() default false;
}1.2 组合结构层次图
@SpringBootApplication
│
├── @SpringBootConfiguration ← 标识当前类是配置类
│ └── @Configuration ← Spring 标准 @Configuration
│ └── @Component ← 标记为 Spring 组件
│
├── @EnableAutoConfiguration ← 开启自动配置
│ └── @AutoConfigurationPackage ← 注册启动类所在包
│ └── @Import(AutoConfigurationPackages.Registrar.class)
│ └── @Import(AutoConfigurationImportSelector.class)
│
└── @ComponentScan ← 组件扫描(含 excludeFilters)
└── excludeFilters:
├── TypeExcludeFilter
└── AutoConfigurationExcludeFilter1.3 各注解职责一览
| 注解 | 职责 | 核心机制 |
|---|---|---|
@SpringBootConfiguration | 标记为 Spring Boot 配置类 | 本质是 @Configuration,用于区分普通 @Configuration |
@EnableAutoConfiguration | 开启自动配置 | 通过 @Import 引入 AutoConfigurationImportSelector |
@ComponentScan | 组件扫描 | 扫描启动类所在包及其子包,注册 @Component 标注的类 |
2. @SpringBootConfiguration 源码解析
2.1 源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}2.2 设计意图 —— 标记区分
Spring Boot 在启动时会校验启动类是否标注了 @SpringBootConfiguration:
// SpringApplication.java
protected void validateConfiguration(Class<?> mainApplicationClass) {
if (mainApplicationClass != null) {
if (!new MergedAnnotations(mainApplicationClass,
SearchStrategy.TYPE_HIERARCHY)
.isPresent(SpringBootConfiguration.class)) {
throw new IllegalStateException(
mainApplicationClass + " is not annotated with "
+ "@SpringBootConfiguration");
}
}
}2.3 proxyBeanMethods 的作用
proxyBeanMethods = true(默认):CGLIB 代理确保@Bean方法返回单例,多次调用返回同一实例。proxyBeanMethods = false:跳过代理,提升启动性能(Lite 模式)。
3. @EnableAutoConfiguration 源码解析
3.1 源码
@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 {};
}3.2 核心机制
通过 @Import(AutoConfigurationImportSelector.class) 注册 ImportSelector 实现,负责:
- 从
AutoConfiguration.imports(3.x)或spring.factories(旧版)读取自动配置类全限定名 - 按条件过滤(
@ConditionalOnClass、@ConditionalOnMissingBean等) - 排序后注册到 Spring 容器
3.3 @AutoConfigurationPackage
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
}将启动类所在包名注册为 Bean,供自动配置类在扫描时使用。
4. SpringFactoriesLoader.loadFactoryNames() 源码全流程
4.1 类定位
SpringFactoriesLoader(org.springframework.core.io.support)负责从 classpath 下的 spring.factories 文件加载工厂实现类列表。
4.2 核心方法源码
// SpringFactoriesLoader.java (Spring Framework 6.x)
public static List<String> loadFactoryNames(Class<?> factoryType,
@Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse)
.getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(
ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) return result; // 缓存命中
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(
FACTORIES_RESOURCE_LOCATION); // META-INF/spring.factories
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils
.loadProperties(new UrlResource(url));
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray(
(String) entry.getValue());
for (String name : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName,
k -> new ArrayList<>()).add(name.trim());
}
}
}
cache.put(classLoader, Collections.unmodifiableMap(result));
} catch (IOException ex) {
throw new IllegalArgumentException(
"Unable to load factories from ["
+ FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}4.3 执行流程
SpringFactoriesLoader.loadFactoryNames()
1. 获取 ClassLoader
2. 检查缓存 (ConcurrentReferenceHashMap)
├─ 命中 → 直接返回
└─ 未命中 → 继续
3. classLoader.getResources("META-INF/spring.factories")
├─ 扫描所有 jar 包中的 spring.factories
└─ 合并为 Properties 对象
4. 按 factoryTypeName 查找实现类列表
└─ key = "org.springframework.boot.autoconfigure.EnableAutoConfiguration"
5. 返回 List<String> (全限定类名列表)4.4 Spring Boot 2.x 加载链路
AutoConfigurationImportSelector.selectImports()
→ getAutoConfigurationEntry()
→ getCandidateConfigurations()
→ SpringFactoriesLoader.loadFactoryNames(
EnableAutoConfiguration.class, classLoader)
→ META-INF/spring.factories
→ key: EnableAutoConfiguration
→ value: 逗号分隔的全限定类名5. AutoConfiguration.imports 加载机制
5.1 机制演进
| 版本 | 配置位置 | 文件格式 |
|---|---|---|
| Spring Boot 2.3- | META-INF/spring.factories | Properties 格式,Key-Value |
| Spring Boot 2.7+ | META-INF/spring/...AutoConfiguration.imports | 每行一个全限定类名 |
| Spring Boot 3.x | 同上(完全移除 spring.factories 支持) | 每行一个类名,支持 # 注释 |
5.2 新机制源码
// AutoConfigurationImportSelector.java (Spring Boot 3.x)
protected List<String> getCandidateConfigurations(
AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 不再走 SpringFactoriesLoader,改为 ImportCandidates
List<String> configurations =
ImportCandidates.load(AutoConfiguration.class,
getBeanClassLoader()).getCandidates();
Assert.notEmpty(configurations,
"No auto configuration classes found in "
+ "META-INF/spring/org.springframework.boot.autoconfigure."
+ "AutoConfiguration.imports");
return configurations;
}5.3 ImportCandidates 源码
// ImportCandidates.java
public final class ImportCandidates {
private static final String LOCATION = "META-INF/spring/%s.imports";
private final List<String> candidates;
public static ImportCandidates load(Class<?> annotation,
ClassLoader classLoader) {
ClassLoader cl = classLoader != null ? classLoader
: ClassUtils.getDefaultClassLoader();
String location = String.format(LOCATION, annotation.getName());
return new ImportCandidates(cl.getResources(location));
}
private ImportCandidates(Enumeration<URL> urls) throws IOException {
List<String> candidates = new ArrayList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(url.openStream(),
StandardCharsets.UTF_8))) {
reader.lines()
.map(String::trim)
.filter(line -> !line.isEmpty() && !line.startsWith("#"))
.forEach(candidates::add);
}
}
this.candidates = Collections.unmodifiableList(candidates);
}
public List<String> getCandidates() { return this.candidates; }
}5.4 文件格式示例
# AutoConfiguration.imports - Spring Boot 3.x
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration5.5 自动配置加载全流程
SpringApplication.run()
→ refreshContext() → refresh()
→ invokeBeanFactoryPostProcessors()
→ ConfigurationClassPostProcessor
→ processConfigBeanDefinitions()
→ ConfigurationClassParser.parse()
→ processImports()
→ AutoConfigurationImportSelector.selectImports()
→ getAutoConfigurationEntry()
├── 1. ImportCandidates.load() → 读取 AutoConfiguration.imports
├── 2. 获取排除列表 (exclusions)
│ ├── @SpringBootApplication(exclude=...)
│ └── spring.autoconfigure.exclude 属性
├── 3. 条件过滤 (OnClassCondition.match())
│ └── 检查 @ConditionalOnClass
├── 4. 排序 (AutoConfigurationSorter)
│ └── @AutoConfigureAfter/@AutoConfigureBefore/@AutoConfigureOrder
└── 5. 返回配置类名数组 → 注册到 BeanDefinitionRegistry6. @ComponentScan 的 excludeFilters 设计原理
6.1 默认 excludeFilters
@ComponentScan(
excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class)
}
)6.2 TypeExcludeFilter —— SPI 扩展排除
public class TypeExcludeFilter implements TypeFilter, EnvironmentAware, BeanFactoryAware {
@Override
public boolean match(MetadataReader metadataReader,
MetadataReaderFactory metadataReaderFactory) throws IOException {
if (this.beanFactory instanceof ListableBeanFactory
&& getClass() == TypeExcludeFilter.class) {
for (TypeExcludeFilter filter : getDelegates()) {
if (filter.match(metadataReader, metadataReaderFactory)) {
return true;
}
}
}
return false;
}
private List<TypeExcludeFilter> getDelegates() {
return ((ListableBeanFactory) this.beanFactory)
.getBeanProvider(TypeExcludeFilter.class)
.orderedStream()
.filter(f -> f.getClass() != TypeExcludeFilter.class)
.collect(Collectors.toList());
}
}设计意图:允许通过 SPI 扩展排除规则,无需修改 @ComponentScan 配置。
6.3 AutoConfigurationExcludeFilter —— 防止自动配置类重复注册
public class AutoConfigurationExcludeFilter implements TypeFilter {
private static final String[] AUTO_CONFIGURATION_ANNOTATIONS = {
"org.springframework.boot.autoconfigure.EnableAutoConfiguration",
"org.springframework.boot.autoconfigure.AutoConfiguration"
};
@Override
public boolean match(MetadataReader metadataReader,
MetadataReaderFactory metadataReaderFactory) throws IOException {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
for (String annotation : AUTO_CONFIGURATION_ANNOTATIONS) {
if (metadata.hasAnnotation(annotation)
|| metadata.hasMetaAnnotation(annotation)) {
return true; // 匹配则排除
}
}
return false;
}
}6.4 为什么要排除自动配置类?
自动配置类通过 AutoConfigurationImportSelector 编程式注册,不应被 @ComponentScan 再次扫描:
- 重复注册:同一个自动配置类被注册两次
- 条件注解失效:
@ConditionalOnClass等条件在@ComponentScan阶段不会被处理 - 顺序错乱:
@AutoConfigureAfter等排序关系无法保证
6.5 excludeFilters 执行时机
@ComponentScan
→ ClassPathBeanDefinitionScanner.doScan()
→ scanCandidateComponents()
→ isCandidateComponent()
→ MetadataReader 读取注解信息
→ match(excludeFilters)
├── TypeExcludeFilter → 委托给 SPI 扩展
└── AutoConfigurationExcludeFilter → 检查 @EnableAutoConfiguration
→ 匹配则跳过7. 启动类加载与代理机制
7.1 SpringApplication.run() 流程
// SpringApplication.java (简化)
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments =
new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(
listeners, bootstrapContext, applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
// 准备上下文 — 加载启动类
prepareContext(bootstrapContext, context, environment,
listeners, applicationArguments, printedBanner);
// ★ 刷新上下文 — 触发自动配置
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
listeners.started(context);
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
listeners.running(context);
return context;
}7.2 prepareContext 中的启动类加载
// SpringApplication.prepareContext() 关键部分
private void prepareContext(...) {
// 注册启动参数 Bean
context.getBeanFactory().registerSingleton(
"springApplicationArguments", applicationArguments);
// 注册 Banner
if (printedBanner != null) {
context.getBeanFactory().registerSingleton(
"springBootBanner", printedBanner);
}
// ★ 加载启动类
load(context, sources.toArray(new Object[0]));
listeners.contextPrepared(context);
bootstrapContext.close(context);
}
// BeanDefinitionLoader.load()
public void load() {
for (Object source : this.sources) { load(source); }
}
private void load(Object source) {
if (source instanceof Class<?>) {
load((Class<?>) source);
}
}
private void load(Class<?> source) {
if (isRegistered(source)) return;
if (isComponent(source)) { // 标注了 @Component 或其派生注解
this.annotatedReader.register(source);
}
}7.3 CGLIB 代理机制
当 proxyBeanMethods = true 时,配置类被 CGLIB 增强:
// ConfigurationClassEnhancer.java
public class ConfigurationClassEnhancer {
private static final Callback[] CALLBACKS = {
new BeanMethodInterceptor(), // 拦截 @Bean 方法
new BeanFactoryAwareMethodInterceptor() // 注入 BeanFactory
};
public Class<?> enhance(Class<?> configClass, ClassLoader classLoader) {
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
return configClass; // 已增强则跳过
}
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configClass);
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setCallbackFilter(new BeanMethodCallbackFilter());
enhancer.setCallbackTypes(CALLBACKS);
return enhancer.createClass();
}
}代理确保 @Bean 方法间调用的单例性:
@SpringBootApplication
public class MyApplication {
@Bean
public A a() { return new A(b()); } // 代理拦截,b() 返回容器单例
@Bean
public B b() { return new B(); }
}8. 实战:Spring Boot 3 项目自动配置加载全过程
8.1 启动类
// com.example.demo.DemoApplication.java
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}8.2 步骤 1:SpringApplication 构造
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从 spring.factories 加载 BootstrapRegistryInitializer
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 加载 ApplicationContextInitializer
setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 加载 ApplicationListener
setListeners(getSpringFactoriesInstances(ApplicationListener.class));
// 推断主启动类
this.mainApplicationClass = deduceMainApplicationClass();
}deduceMainApplicationClass() 通过堆栈回溯找到 main 方法所在类:
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement element : stackTrace) {
if ("main".equals(element.getMethodName())) {
return Class.forName(element.getClassName());
}
}
} catch (ClassNotFoundException ex) { /* ignore */ }
return null;
}8.3 步骤 2:refreshContext() → ConfigurationClassPostProcessor
自动配置加载的入口在 refresh() → invokeBeanFactoryPostProcessors() 阶段:
// ConfigurationClassPostProcessor
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(...);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry); // 核心处理
}8.4 步骤 3:处理 @Import → AutoConfigurationImportSelector
ConfigurationClassParser.processImports() 发现 @Import(AutoConfigurationImportSelector.class):
// processImports() 关键分支
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(
candidateClass, ...);
// 调用 selectImports() 获取自动配置类名
String[] importClassNames =
selector.selectImports(currentSourceClass.getMetadata());
// 递归处理返回的配置类
processImports(configClass, currentSourceClass,
collectImports(importClassNames), exclusionFilter, false);
}
}8.5 步骤 4:getAutoConfigurationEntry() —— 自动配置加载核心
protected AutoConfigurationEntry getAutoConfigurationEntry(
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) return EMPTY_ENTRY;
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 1. 从 AutoConfiguration.imports 获取候选类
List<String> configurations = getCandidateConfigurations(
annotationMetadata, attributes);
// 2. 去重
configurations = removeDuplicates(configurations);
// 3. 获取排除列表
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 4. ★ 条件过滤 (OnClassCondition 等)
configurations = getConfigurationClassFilter().filter(configurations);
// 5. 触发事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}8.6 步骤 5:条件过滤示例 —— RedisAutoConfiguration
@AutoConfiguration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) { ... }
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) { ... }
}| 条件注解 | 检查内容 | 结果 |
|---|---|---|
@ConditionalOnClass(RedisOperations.class) | classpath 中是否存在 RedisOperations | 有依赖 → 通过 |
@ConditionalOnMissingBean(name = "redisTemplate") | 容器中是否已有同名 Bean | 未自定义 → 通过 |
@ConditionalOnSingleCandidate(RedisConnectionFactory.class) | 容器中是否只有一个候选 | 有连接池 → 通过 |
8.7 排序与注册
AutoConfigurationSorter 根据 @AutoConfigureAfter/@AutoConfigureBefore/@AutoConfigureOrder 进行拓扑排序:
@AutoConfiguration(after = {DataSourceAutoConfiguration.class})
@ConditionalOnClass(DataSource.class)
public class MybatisAutoConfiguration { ... }8.8 全流程总图
SpringApplication.run(DemoApplication.class)
│
├─ 1. 创建 SpringApplication 实例
│ ├─ 推断 webApplicationType
│ ├─ 加载 spring.factories → initializers/listeners
│ └─ 推断 mainApplicationClass
│
├─ 2. run()
│ ├─ 创建 BootstrapContext
│ ├─ prepareEnvironment() → Environment
│ ├─ printBanner()
│ ├─ createApplicationContext()
│ ├─ prepareContext() → load(启动类)
│ │ └─ BeanDefinitionLoader → AnnotatedBeanDefinitionReader.register()
│ │
│ ├─ ★ refreshContext()
│ │ └─ AbstractApplicationContext.refresh()
│ │ ├─ prepareRefresh()
│ │ ├─ obtainFreshBeanFactory()
│ │ ├─ ★ invokeBeanFactoryPostProcessors()
│ │ │ └─ ConfigurationClassPostProcessor
│ │ │ └─ processConfigBeanDefinitions()
│ │ │ └─ ConfigurationClassParser.parse()
│ │ │ └─ processImports()
│ │ │ └─ AutoConfigurationImportSelector
│ │ │ └─ selectImports()
│ │ │ └─ getAutoConfigEntry()
│ │ │ ├─ ImportCandidates.load()
│ │ │ │ → AutoConfiguration.imports
│ │ │ ├─ 去重 & 排除
│ │ │ ├─ ★ 条件过滤(OnClassCondition)
│ │ │ └─ 排序 → 返回
│ │ │
│ │ ├─ registerBeanPostProcessors()
│ │ ├─ initMessageSource()
│ │ ├─ ★ finishBeanFactoryInitialization()
│ │ │ └─ 实例化非懒加载单例 Bean
│ │ └─ finishRefresh()
│ │
│ ├─ afterRefresh()
│ ├─ listeners.started() → ApplicationStartedEvent
│ └─ callRunners() → CommandLineRunner/ApplicationRunner
│
└─ 启动完成9. 常见问题与源码级分析
9.1 为什么启动类会被 CGLIB 代理?
当 proxyBeanMethods = true(默认)时,Spring 将 @Configuration 派生类通过 CGLIB 增强以拦截 @Bean 方法调用。如果启动类声明了 @Bean 方法就会产生代理。
9.2 @SpringBootApplication 的扫描范围?
不指定 basePackages 时,以 标注该注解的类所在包 为根包:
com.example.demo
├── DemoApplication.java ← @SpringBootApplication 在此
├── controller/ ← 扫描到
├── service/ ← 扫描到
├── repository/ ← 扫描到
└── config/ ← 扫描到com.other 包不会被扫描,除非手动指定 scanBasePackages。
9.3 自动配置过滤链
// AutoConfigurationImportSelector.getConfigurationClassFilter()
private ConfigurationClassFilter getConfigurationClassFilter() {
if (this.configurationClassFilter == null) {
List<AutoConfigurationImportFilter> filters =
SpringFactoriesLoader.loadFactories(
AutoConfigurationImportFilter.class,
this.beanClassLoader);
for (AutoConfigurationImportFilter filter : filters) {
filter.setAutoConfigurationMetadata(getAutoConfigurationMetadata());
}
this.configurationClassFilter = new ConfigurationClassFilter(
this.autoConfigurationMetadata, filters);
}
return this.configurationClassFilter;
}默认注册的三个 AutoConfigurationImportFilter:
| Filter 实现 | 功能 |
|---|---|
OnClassCondition | 检查 @ConditionalOnClass 指定的类是否存在 |
OnBeanCondition | 检查 @ConditionalOnBean/@ConditionalOnMissingBean |
OnWebApplicationCondition | 检查 @ConditionalOnWebApplication |
9.4 spring.factories → AutoConfiguration.imports 迁移
Spring Boot 3.x 不再支持从 spring.factories 加载自动配置类:
// Spring Boot 3.x — 不再使用 SpringFactoriesLoader
// List<String> configs = SpringFactoriesLoader.loadFactoryNames(
// EnableAutoConfiguration.class, getBeanClassLoader());
// 改为 ImportCandidates
List<String> configurations =
ImportCandidates.load(AutoConfiguration.class,
getBeanClassLoader()).getCandidates();同时引入 @AutoConfiguration 注解,要求自动配置类必须标注此注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@AutoConfigureBefore
@AutoConfigureAfter
public @interface AutoConfiguration {
@AliasFor(annotation = Configuration.class, attribute = "proxyBeanMethods")
boolean proxyBeanMethods() default true;
@AliasFor(annotation = AutoConfigureBefore.class, attribute = "value")
Class<?>[] before() default {};
@AliasFor(annotation = AutoConfigureAfter.class, attribute = "value")
Class<?>[] after() default {};
String[] beforeName() default {};
String[] afterName() default {};
}10. 总结
| 维度 | 说明 |
|---|---|
| 本质 | @SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan |
| 配置类 | @SpringBootConfiguration 是 @Configuration 派生注解,支持 proxyBeanMethods 控制代理 |
| 自动配置入口 | @EnableAutoConfiguration → @Import(AutoConfigurationImportSelector.class) |
| 加载机制(3.x) | ImportCandidates.load() → AutoConfiguration.imports 文件 |
| 加载机制(旧版) | SpringFactoriesLoader.loadFactoryNames() → spring.factories 文件 |
| 条件过滤 | OnClassCondition / OnBeanCondition / OnWebApplicationCondition 组成过滤链 |
| 扫描排除 | TypeExcludeFilter(SPI 扩展) + AutoConfigurationExcludeFilter(防重复注册) |
| 启动流程 | run() → refreshContext() → invokeBeanFactoryPostProcessors() → ConfigurationClassPostProcessor → AutoConfigurationImportSelector |
@SpringBootApplication 虽然是一个简单的注解,但背后串联起了 Spring Boot 整个自动配置体系。理解其源码实现,对于诊断启动问题、优化启动性能、自定义自动配置都具有重要意义。
参考源码:
org.springframework.boot:spring-boot-autoconfigureorg.springframework:spring-contextorg.springframework:spring-core- Spring Boot 3.x
AutoConfigurationImportSelector- Spring Framework 6.x
ConfigurationClassParser