????????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()
:
@Override
public 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<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {// ...Enumeration<URL> 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 Configure
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自動配置的核心思想是"條件化配置",通過一系列@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 {@Overrideprotected 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@ConditionalOnMissingBeanpublic 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的自動配置機制通過這種靈活的條件化方式,既保證了"約定優于配置"的便利性,又提供了足夠的靈活性來覆蓋默認行為。