Spring Boot 自动装配是其最核心、最具革命性的特性之一,它极大地简化了 Spring 应用的开发。其核心原理可以概括为:“约定优于配置” 和 “自动发现与注册”。
下面我们通过一个清晰的流程和核心源码解析来深入理解它。
一、核心思想
在没有自动装配之前,我们需要在 XML 或 Java 配置类中手动声明大量的 Bean(如 DataSource、EntityManagerFactory、TransactionManager 等)。Spring Boot 自动装配的目标是:当项目的 Classpath 下存在某个特定的类、配置或依赖时,Spring Boot 会自动为我们配置好这些 Bean,而无需我们手动编写配置代码。
二、实现原理详解
自动装配的实现主要依赖于以下几个核心组件:
- @SpringBootApplication 注解
- @EnableAutoConfiguration 注解
- spring.factories 文件
- @Conditional 系列条件注解
让我们通过启动流程来串联这些组件:
步骤 1:启动入口
每个 Spring Boot 应用的启动类上都有一个 @SpringBootApplication 注解。- @SpringBootApplication
- public class SpringSecurityApplication {
- public static void main(String[] args) {
- SpringApplication.run(SpringSecurityApplication.class, args);
- }
- }
复制代码 @SpringBootApplication 是一个复合注解,它包含了许多其他注解,其中最关键的一个就是@EnableAutoConfiguration。- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @SpringBootConfiguration
- @EnableAutoConfiguration // 关键注解!
- @ComponentScan
- public @interface SpringBootApplication {
- // ...
- }
复制代码 步骤 2:开启自动配置
@EnableAutoConfiguration 是开启自动装配的“开关”。- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @AutoConfigurationPackage
- @Import(AutoConfigurationImportSelector.class) // 核心!
- public @interface EnableAutoConfiguration {
- // ...
- }
复制代码 这个注解的核心是 @Import(AutoConfigurationImportSelector.class)。@Import 是 Spring 框架的注解,用于向容器中导入组件。这里导入了一个 AutoConfigurationImportSelector。
步骤 3:自动配置选择器
AutoConfigurationImportSelector 是整个自动装配过程的“大脑”。它的 selectImports 方法负责决定需要向 Spring 容器中导入哪些自动配置类。- public class AutoConfigurationImportSelector implements ... {
- @Override
- public String[] selectImports(AnnotationMetadata annotationMetadata) {
- // 核心方法:获取所有需要自动配置的类的全限定名
- List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
- // ... (后续会有去重、过滤等操作)
- return StringUtils.toStringArray(configurations);
- }
- protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
- // 从 spring.factories 文件中加载配置
- List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
- return configurations;
- }
- protected Class<?> getSpringFactoriesLoaderFactoryClass() {
- return EnableAutoConfiguration.class;
- }
- }
复制代码 关键点在于 SpringFactoriesLoader.loadFactoryNames(...) 这一行。它会去扫描所有依赖 jar 包中的 META-INF/spring.factories 文件。
步骤 4:spring.factories - 自动配置的清单
spring.factories 是一个标准的 Java properties 文件,格式为 `key=value1,value2,value3`。
在 spring-boot-autoconfigure 这个核心 jar 包的 META-INF/spring.factories 文件中,有一个以 EnableAutoConfiguration 为 key 的配置项,它的 value 是一个长长的、用逗号分隔的自动配置类的全限定名列表。
示例 (META-INF/spring.factories):- # Auto Configure
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
- org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
- org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
- org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
- org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
- org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
- org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
- org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
- org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
- org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
- org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
- org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
- org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
- org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
- ... (这里列出了上百个自动配置类)
复制代码 AutoConfigurationImportSelector 就是通过读取这个文件,获取了所有候选的自动配置类。
步骤 5:条件注解 - 按需加载
Spring Boot 不可能把所有 spring.factories 里定义的配置类都进行加载,否则你的应用会包含大量你不需要的 Bean,导致内存浪费和启动缓慢。
条件注解 (@Conditional) 就是用来解决这个问题的。它们被标注在每一个自动配置类上,只有当条件满足时,这个自动配置类才会生效,其内部定义的 Bean 才会被创建。
常见的条件注解:
@ConditionalOnClass:当 Classpath 下存在指定的类时生效。
@ConditionalOnMissingBean:当 Spring 容器中不存在指定类型的 Bean 时生效。(这为我们提供了覆盖默认 Bean 的机会)
@ConditionalOnProperty:当指定的配置属性有特定值时生效。
@ConditionalOnWebApplication:当应用是 Web 应用时生效。
@ConditionalOnJava:当运行在指定的 Java 版本时生效。
步骤 6:自动配置类的工作
让我们以 DataSourceAutoConfiguration 为例,看看一个典型的自动配置类长什么样:- @Configuration(proxyBeanMethods = false) // 声明这是一个配置类
- @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) // 条件1:存在相关类
- @ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory") // 条件2:不存在 R2DBC 连接工厂
- @EnableConfigurationProperties(DataSourceProperties.class) // 使 DataSourceProperties 配置属性生效
- public class DataSourceAutoConfiguration {
- @Configuration
- @Conditional(EmbeddedDatabaseCondition.class) // 内嵌数据库条件
- @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
- @Import(EmbeddedDataSourceConfiguration.class)
- protected static class EmbeddedDatabaseConfiguration {
- }
- @Configuration
- @Conditional(PooledDataSourceCondition.class) // 连接池数据源条件
- @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
- @Import({ DataSourceConfiguration.Hikari.class,
- DataSourceConfiguration.Tomcat.class,
- DataSourceConfiguration.Dbcp2.class,
- DataSourceConfiguration.Generic.class })
- protected static class PooledDataSourceConfiguration {
- }
- // ... 其他内部配置类
- }
复制代码 这个配置类做了以下几件事:
1. 只有在 Classpath 下存在 DataSource 和 EmbeddedDatabaseType 类时(即引入了数据库驱动),它才会生效。
2. 它导入了 DataSourceProperties 类,这个类绑定了 application.properties 中以 spring.datasource 为前缀的配置。
3. 它定义了两个内部配置类,分别用于创建内嵌数据库(如 H2)和连接池数据源(如 HikariCP)。具体使用哪个,由 PooledDataSourceCondition 等条件决定。
4. 只有在容器中不存在 DataSource 类型的 Bean 时,它才会创建默认的 Bean。这允许我们自己在配置类中定义一个 DataSource Bean 来完全覆盖默认的自动配置。
三、总结与流程图
自动装配流程总结:
- 启动应用:@SpringBootApplication -> @EnableAutoConfiguration。
- 导入选择器:@Import(AutoConfigurationImportSelector.class) 开始工作。
- 加载清单:AutoConfigurationImportSelector 读取所有 jar 包的 META-INF/spring.factories 文件,获取 EnableAutoConfiguration 对应的所有自动配置类的全类名。
- 过滤筛选:根据这些配置类上标注的 @Conditional 系列条件注解,按需进行筛选,只加载满足当前应用环境(Classpath、配置、已存在的 Bean 等)的配置类。
- 执行配置:被选中的自动配置类开始执行,向容器中注入预先定义好的、满足生产需求的 Bean。
四、如何调试和查看自动装配
- 开启调试日志:在 application.properties 中添加 debug=true。启动时,控制台会打印出所有自动配置类的评估报告,分为两部分:
- Positive matches:已启用的自动配置。
- Negative matches:未启用的自动配置及原因。
- 查看已启用的配置:使用 Spring Actuator 的 /conditions 端点(如果引入了 Actuator 依赖),它可以提供一个更详细的 HTML 报告。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |