SpringBoot学习路径二--Spring Boot自动配置原理深度解析
SpringBoot最核心的功能就是自动装配,Starter作为SpringBoot的核心功能之一,基于自动配置代码提供了自动配置模块及依赖的能力,让软件集成变得简单、易用。使用SpringBoot时,我们只需引I人对应的Starter,SpringBoot启动时便会自动加载相关依赖,集成相关功能,这便是SpringBoot的自动装配功能。
简单概括其自动配置的原理:由@SpringBootAppliction组合注解中的@EnableAutoConfiguration注解开启自动配置,加载spring.factories文件中注册的各种默认定义的XxxAutoConfiguration配置类,并且该类可指定@Conditional条件注解,当其@Conditional条件注解生效时,实例化该配置类中定义的Bean,并注入Spring上下文。
一、自动配置核心机制
1. @SpringBootApplication注解
自动配置的入口是@SpringBootApplication
注解,它实际上是一个复合注解:
@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 { // ...}
其中最关键的是@EnableAutoConfiguration
注解。
2. @EnableAutoConfiguration注解
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration { // ...}
这个注解通过@Import
导入了AutoConfigurationImportSelector
类,这是自动配置的核心实现类。
二、自动配置核心流程
1. AutoConfigurationImportSelector
AutoConfigurationImportSelector
实现了DeferredImportSelector
接口,它的核心方法是selectImports()
:
@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
关键调用链:
-
getAutoConfigurationEntry()
-
getCandidateConfigurations()
-
loadFactoryNames()
-
loadSpringFactories()
2. 加载自动配置类
在loadSpringFactories()
方法中,会从META-INF/spring.factories
文件中加载配置:
private static Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader) { // ... Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION); // ...}
FACTORIES_RESOURCE_LOCATION
常量的值为\"META-INF/spring.factories\"
。
3. spring.factories文件
以spring-boot-autoconfigure模块为例,它的META-INF/spring.factories
文件中定义了大量的自动配置类:
# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\\org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\\...
三、条件化自动配置
Spring Boot自动配置的核心思想是\"条件化配置\",通过一系列@Conditional
注解实现。
1. 常用条件注解
-
@ConditionalOnClass
:类路径下存在指定类时生效 -
@ConditionalOnMissingClass
:类路径下不存在指定类时生效 -
@ConditionalOnBean
:容器中存在指定Bean时生效 -
@ConditionalOnMissingBean
:容器中不存在指定Bean时生效 -
@ConditionalOnProperty
:配置文件中存在指定属性时生效 -
@ConditionalOnResource
:类路径下存在指定资源时生效 -
@ConditionalOnWebApplication
:是Web应用时生效 -
@ConditionalOnNotWebApplication
:不是Web应用时生效
2. 条件注解实现原理
以@ConditionalOnClass
为例,其实现类是OnClassCondition
:
@Order(Ordered.HIGHEST_PRECEDENCE)class OnClassCondition extends FilteringSpringBootCondition { @Override protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { // ... ConditionOutcome outcome = getOutcome(metadata); // ... } private ConditionOutcome getOutcome(ConditionMetadata metadata) { // 检查类是否存在 ClassLoader classLoader = getClass().getClassLoader(); String[] onClasses = metadata.getConditionalOnClass(); for (String onClass : onClasses) { if (!ClassUtils.isPresent(onClass, classLoader)) { return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class) .didNotFind(\"required class\").items(Style.QUOTE, onClass)); } } return null; }}
四、自动配置执行流程
-
启动阶段:
-
SpringApplication.run()启动应用
-
调用refreshContext()刷新应用上下文
-
-
配置类解析:
-
ConfigurationClassPostProcessor处理所有配置类
-
解析@SpringBootApplication和@EnableAutoConfiguration
-
-
自动配置类加载:
-
AutoConfigurationImportSelector加载spring.factories中的配置类
-
过滤掉不满足条件的配置类
-
-
Bean定义注册:
-
将筛选后的自动配置类注册为Bean定义
-
后续由Spring容器实例化这些Bean
-
五、自动配置示例分析
以DataSourceAutoConfiguration为例:
@Configuration(proxyBeanMethods = false)@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })@ConditionalOnMissingBean(type = \"io.r2dbc.spi.ConnectionFactory\")@EnableConfigurationProperties(DataSourceProperties.class)@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })public class DataSourceAutoConfiguration { @Configuration(proxyBeanMethods = false) @Conditional(EmbeddedDatabaseCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import(EmbeddedDataSourceConfiguration.class) protected static class EmbeddedDatabaseConfiguration { } @Configuration(proxyBeanMethods = false) @Conditional(PooledDataSourceCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class }) protected static class PooledDataSourceConfiguration { } // ...}
这个自动配置类展示了典型的条件化配置:
-
只有在类路径下存在DataSource和EmbeddedDatabaseType时才生效
-
容器中没有ConnectionFactory时才生效
-
根据不同的条件导入不同的配置
六、自动配置调试技巧
-
查看生效的自动配置:
在application.properties中添加:debug=true
启动时会输出所有自动配置类的评估结果。
-
排除特定自动配置:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
-
查看自动配置条件:
通过/actuator/conditions
端点(需要actuator依赖)可以查看详细的自动配置条件评估报告。
七、自定义自动配置
-
创建
META-INF/spring.factories
文件 -
定义自己的自动配置类
-
使用合适的条件注解
@Configuration@ConditionalOnClass(MyService.class)@EnableConfigurationProperties(MyServiceProperties.class)public class MyServiceAutoConfiguration { @Bean @ConditionalOnMissingBean public MyService myService(MyServiceProperties properties) { return new MyService(properties); }}
在spring.factories
中注册:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\com.example.MyServiceAutoConfiguration
八、自动配置的底层原理总结
-
SPI机制:通过
META-INF/spring.factories
实现扩展点加载 -
条件评估:通过
Condition
接口实现条件化配置 -
延迟加载:通过
DeferredImportSelector
实现配置类的延迟处理 -
配置优先级:通过
@AutoConfigureOrder
和@Order
控制配置顺序
Spring Boot的自动配置机制通过这种灵活的条件化方式,既保证了\"约定优于配置\"的便利性,又提供了足够的灵活性来覆盖默认行为。