SpringBoot核心原理深度剖析:自动配置是如何实现的?
SpringBoot核心原理深度剖析:自动配置是如何实现的?
- 前言
- 一、什么是自动配置?
- 二、自动配置的入口:`@SpringBootApplication`
- 三、`@EnableAutoConfiguration` 做了什么?
- 四、`AutoConfigurationImportSelector` 核心流程
- 五、`getAutoConfigurationEntry` 核心逻辑
- 六、从哪里加载候选配置类?
- 七、自动配置的核心:条件注解
- 八、完整流程图
- 九、实战:手写一个自定义 Starter
- 十、常见问题与总结
- Q1:自动配置类什么时候不生效?
- Q2:如何查看当前哪些自动配置生效?
- Q3:如何覆盖自动配置?
- 总结
🌺The Begin🌺点点关注,收藏不迷路🌺 ⬇ ⬇ 底部 ⬇ ⬇ |
前言
用过 SpringBoot 的同学都知道,它最大的特点就是“约定大于配置”。我们只需要引入一个starter,几乎不用写任何配置,就能直接使用 Redis、MongoDB、JDBC、RabbitMQ 等各种中间件。这一切的背后,正是 SpringBoot 的自动配置机制。
那么问题来了:SpringBoot 到底是怎么做到自动配置的?它的底层原理是什么?
今天这篇文章,我会带大家手撕源码 + 流程图 + 案例,彻底搞懂 SpringBoot 自动配置的底层实现。
一、什么是自动配置?
简单说:自动配置 = 根据类路径下的依赖 + 配置文件条件,自动创建并注册对应的 Bean。
比如:
- 引入
spring-boot-starter-data-redis→ 自动创建RedisTemplate - 引入
spring-boot-starter-web→ 自动配置DispatcherServlet、Tomcat、Jackson
不需要@EnableXXX,不需要手动写@Bean。
二、自动配置的入口:@SpringBootApplication
我们知道,启动类上都会加这个注解:
@SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(DemoApplication.class,args);}}点进去看源码:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration// 关键!@ComponentScanpublic@interfaceSpringBootApplication{}核心就是@EnableAutoConfiguration。
三、@EnableAutoConfiguration做了什么?
再点进去:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)// 关键!public@interfaceEnableAutoConfiguration{}这里通过@Import引入了AutoConfigurationImportSelector,它是自动配置的真正实现者。
四、AutoConfigurationImportSelector核心流程
AutoConfigurationImportSelector实现了ImportSelector接口,其核心方法是:
@OverridepublicString[]selectImports(AnnotationMetadataannotationMetadata){// 判断是否开启自动配置if(!isEnabled(annotationMetadata)){returnNO_IMPORTS;}// 获取所有自动配置类的全限定名AutoConfigurationEntryautoConfigurationEntry=getAutoConfigurationEntry(annotationMetadata);returnStringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}五、getAutoConfigurationEntry核心逻辑
这个方法做了几件事:
- 获取
@EnableAutoConfiguration的排除项(exclude) - 从
META-INF/spring.factories或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中加载候选配置类 - 过滤掉排除项
- 去重、排序
- 返回最终要加载的配置类
protectedAutoConfigurationEntrygetAutoConfigurationEntry(AnnotationMetadataannotationMetadata){// 1. 获取 exclude 列表Set<String>exclusions=getExclusions(annotationMetadata);// 2. 加载所有候选配置类List<String>configurations=getCandidateConfigurations(annotationMetadata);// 3. 移除 exclude 的configurations.removeAll(exclusions);// 4. 过滤(比如条件注解)configurations=filter(configurations);returnnewAutoConfigurationEntry(configurations,exclusions);}六、从哪里加载候选配置类?
核心方法getCandidateConfigurations:
protectedList<String>getCandidateConfigurations(AnnotationMetadatametadata,AnnotationAttributesattributes){List<String>configurations=SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());returnconfigurations;}loadFactoryNames会扫描所有 jar 包下的META-INF/spring.factories文件,key =EnableAutoConfiguration对应的配置类。
示例(spring-boot-autoconfigure 包中的部分内容):
# 文件:META-INF/spring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ ...注意:SpringBoot 2.7 之后部分配置迁移到
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
七、自动配置的核心:条件注解
自动配置类并不会无条件加载,而是通过@Conditional系列注解控制。
举例:DataSourceAutoConfiguration
@Configuration(proxyBeanMethods=false)@ConditionalOnClass({DataSource.class,EmbeddedDatabaseType.class})@ConditionalOnMissingBean(type="io.r2dbc.spi.ConnectionFactory")@EnableConfigurationProperties(DataSourceProperties.class)@Import(DataSourcePoolMetadataProvidersConfiguration.class)publicclassDataSourceAutoConfiguration{// ...}常见条件注解:
| 注解 | 作用 |
|---|---|
@ConditionalOnClass | 类路径下存在某类才生效 |
@ConditionalOnMissingBean | 容器中无某 Bean 才生效 |
@ConditionalOnProperty | 配置文件中存在某属性才生效 |
@ConditionalOnWebApplication | 是 Web 环境才生效 |
这就是为什么你配了spring.datasource.url,自动配置才会创建DataSource。
八、完整流程图
+-----------------------------------+ | 启动类 @SpringBootApplication | +-----------------------------------+ | v +-----------------------------------+ | @EnableAutoConfiguration | +-----------------------------------+ | v +-----------------------------------+ | AutoConfigurationImportSelector | +-----------------------------------+ | v +-----------------------------------+ | getAutoConfigurationEntry | | - 获取 exclude | | - 加载 META-INF/spring.factories | | - 过滤 exclude | | - @Conditional 过滤 | +-----------------------------------+ | v +-----------------------------------+ | 加载自动配置类 (如 RedisAutoConf) | +-----------------------------------+ | v +-----------------------------------+ | 条件注解检查 (@ConditionalOnXX) | | - 存在类? | | - 存在配置? | | - 存在 Bean? | +-----------------------------------+ | v +-----------------------------------+ | 创建并注册相应的 Bean 到容器 | +-----------------------------------+九、实战:手写一个自定义 Starter
- 创建自动配置类
@Configuration@ConditionalOnClass(HelloService.class)@EnableConfigurationProperties(HelloProperties.class)publicclassHelloAutoConfiguration{@Bean@ConditionalOnMissingBeanpublicHelloServicehelloService(HelloPropertiesproperties){returnnewHelloService(properties);}}- 编写配置属性类
@ConfigurationProperties(prefix="hello")publicclassHelloProperties{privateStringname="world";privateStringmsg="hello";// getter/setter}- 在
META-INF/spring.factories中注册
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.starter.HelloAutoConfiguration这样别人引入你的 starter 后,只要配置hello.name=xxx,HelloService就会自动注入容器。
十、常见问题与总结
Q1:自动配置类什么时候不生效?
- 被 exclude 手动排除
- 条件注解不满足(类不存在 / 属性未配置 / Bean 已存在)
Q2:如何查看当前哪些自动配置生效?
启动时加--debug,可以看到:
Positive matches: DataSourceAutoConfiguration matched Negative matches: RedisAutoConfiguration: missing required class org.springframework.data.redis.core.RedisOperationsQ3:如何覆盖自动配置?
- 自己定义同名的
@Bean - 使用
spring.autoconfigure.exclude排除 - 修改配置属性(如
spring.datasource.url)
总结
SpringBoot 自动配置的本质:
- 入口:
@EnableAutoConfiguration - 加载器:
AutoConfigurationImportSelector - 配置来源:
META-INF/spring.factories或AutoConfiguration.imports - 生效控制:
@Conditional系列条件注解 - 属性绑定:
@ConfigurationProperties+@EnableConfigurationProperties
理解了这个流程,你就能:
- 快速定位 Bean 为什么生效 / 不生效
- 自定义自己的 Starter
- 看懂 SpringBoot 源码的核心脉络
希望这篇文章能帮你真正搞懂 SpringBoot 自动配置的原理。如果觉得有收获,欢迎点赞 + 收藏 + 评论交流!
🌺The End🌺点点关注,收藏不迷路🌺 ⬆ ⬆ 顶部 ⬆ ⬆ |
