Spring Boot 的自動配置是其 "約定大于配置" 理念的核心實現,它能自動配置 Spring 應用所需的各種組件,大幅減少手動配置。下面從核心注解、加載流程、條件過濾等方面詳細講解其原理,并結合關鍵源碼說明。
一、自動配置的入口:@SpringBootApplication 注解
Spring Boot 應用的啟動類通常標注@SpringBootApplication
,這個注解是自動配置的起點,它是一個 "復合注解",包含三個核心注解:
@SpringBootConfiguration
:本質是@Configuration
,標識當前類是配置類@ComponentScan
:掃描當前包及子包的組件(如@Component
、@Service
等)@EnableAutoConfiguration
:啟用自動配置的核心注解
源碼:@SpringBootApplication
java運行
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 等同于@Configuration
@ComponentScan(excludeFilters = { // 掃描組件@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
@EnableAutoConfiguration // 關鍵:啟用自動配置
public @interface SpringBootApplication {// 排除指定的自動配置類Class<?>[] exclude() default {};String[] excludeName() default {};// ... 其他屬性
}
二、@EnableAutoConfiguration:自動配置的開關
@EnableAutoConfiguration
的核心作用是觸發 Spring 容器自動導入符合條件的配置類,其實現依賴@Import
注解導入AutoConfigurationImportSelector
類。
源碼:@EnableAutoConfiguration
java運行
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 自動注冊當前包為基礎包(用于掃描@Entity等)
@Import(AutoConfigurationImportSelector.class) // 關鍵:導入選擇器
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";// 排除不需要的自動配置類Class<?>[] exclude() default {};String[] excludeName() default {};
}
三、AutoConfigurationImportSelector:自動配置類的 "導入器"
AutoConfigurationImportSelector
是自動配置的核心類,它通過selectImports
方法篩選并導入符合條件的自動配置類,流程如下:
1. 核心方法:selectImports
該方法返回需要導入的自動配置類全類名數組,核心邏輯是獲取候選配置類并過濾。
java運行
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, etc. {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) { // 檢查是否啟用自動配置(默認啟用)return NO_IMPORTS;}// 1. 加載自動配置的元數據(條件注解等信息)AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);// 2. 獲取所有候選的自動配置類AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}// 關鍵:獲取自動配置入口(篩選候選類)protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {// ... 檢查是否啟用(省略)// 1. 獲取所有候選的自動配置類(從spring.factories加載)List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 2. 去重configurations = removeDuplicates(configurations);// 3. 排除用戶指定的自動配置類(通過exclude屬性)Set<String> exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);// 4. 基于條件注解過濾(核心:只保留符合條件的配置類)configurations = filter(configurations, autoConfigurationMetadata);// ... 其他處理(發布事件等)return new AutoConfigurationEntry(configurations, exclusions);}
}
2. 加載候選配置類:getCandidateConfigurations
getCandidateConfigurations
通過SpringFactoriesLoader
從類路徑下的META-INF/spring.factories
文件中加載自動配置類。
java運行
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {// 從spring.factories中加載key為EnableAutoConfiguration的配置類List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. " +"If you are using a custom packaging, make sure that file is correct.");return configurations;
}// 指定加載的類型為EnableAutoConfiguration
protected Class<?> getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class;
}
四、SpringFactoriesLoader:SPI 機制的實現
SpringFactoriesLoader
是 Spring 的一種 SPI(Service Provider Interface)實現,用于從類路徑的META-INF/spring.factories
文件中加載指定類型的實現類。
源碼:SpringFactoriesLoader.loadFactoryNames
java運行
public final class SpringFactoriesLoader {public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();// 加載所有spring.factories文件,返回key為接口名、value為實現類列表的Mapreturn loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {return result;}try {// 查找類路徑下所有META-INF/spring.factories文件Enumeration<URL> urls = (classLoader != null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);// 解析文件為Properties(key=接口全類名,value=實現類全類名逗號分隔)Properties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<?, ?> entry : properties.entrySet()) {String factoryTypeName = ((String) entry.getKey()).trim();for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {result.add(factoryTypeName, factoryImplementationName.trim());}}}cache.put(classLoader, result);return result;}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);}}
}
spring.factories 文件示例
Spring Boot 的spring-boot-autoconfigure
包中包含META-INF/spring.factories
,其中定義了大量自動配置類:
properties
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
# ... 其他數百個自動配置類
五、條件注解:過濾生效的自動配置類
從spring.factories
加載的候選配置類并非全部生效,Spring Boot 通過條件注解(@Conditional
系列)篩選符合當前環境的配置類。
常見條件注解:
@ConditionalOnClass
:類路徑存在指定類時生效@ConditionalOnMissingClass
:類路徑不存在指定類時生效@ConditionalOnBean
:容器中存在指定 Bean 時生效@ConditionalOnMissingBean
:容器中不存在指定 Bean 時生效@ConditionalOnProperty
:配置文件中存在指定屬性時生效@ConditionalOnWebApplication
:當前是 Web 應用時生效
示例:DispatcherServletAutoConfiguration
Spring MVC 的 DispatcherServlet 自動配置類,通過條件注解控制生效時機:
java運行
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET) // 僅在Servlet Web應用中生效
@ConditionalOnClass(DispatcherServlet.class) // 類路徑存在DispatcherServlet時生效
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) // 在指定配置類之后加載
public class DispatcherServletAutoConfiguration {// 定義DispatcherServlet的Bean@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)@ConditionalOnMissingBean(DispatcherServlet.class) // 容器中沒有DispatcherServlet時才創建public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {DispatcherServlet dispatcherServlet = new DispatcherServlet();dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());// ... 配置其他屬性return dispatcherServlet;}
}
六、自動配置的完整流程總結
- 啟動觸發:
@SpringBootApplication
包含@EnableAutoConfiguration
,開啟自動配置。 - 導入選擇器:
@EnableAutoConfiguration
通過@Import
導入AutoConfigurationImportSelector
。 - 加載候選類:
AutoConfigurationImportSelector
通過SpringFactoriesLoader
從META-INF/spring.factories
加載所有EnableAutoConfiguration
對應的自動配置類。 - 過濾配置類:
- 排除用戶指定的類(
exclude
屬性)。 - 通過條件注解(如
@ConditionalOnClass
)篩選符合當前環境的配置類。
- 排除用戶指定的類(
- 注冊 Bean:生效的自動配置類(
@Configuration
)通過@Bean
向容器注冊組件,完成自動配置。
通過這套機制,Spring Boot 實現了 "引入 starter 依賴即可自動配置組件" 的便捷性,開發者無需手動編寫大量 XML 或 Java 配置。