個人博客:槿蘇的知識鋪
一、什么是自動裝配
SpringBoot 定義了一套介面規范,這套規范規定:SpringBoot在啟動時會掃描外部參考jar包中的META-INF/spring.factories檔案,將檔案中配置的型別資訊加載到Spring容器,并執行類中定義的各種操作,對于外部jar包來說,只需要按照SpringBoot定義的標準,就能將自己的功能裝配到SpringBoot中,
二、自動裝配的實作原理
自動裝配的實作,離不開SpringBootApplication這個核心注解,查看這個注解的原始碼,我們會發現在SpringBootApplication注解上,存在著幾個注解,其中SpringBootConfiguration、EnableAutoConfiguration、ComponentScan這三個注解是需要我們注意的,
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
(1) ComponentScan
掃描被
@Component 、@Service注解的bean,該注解默認會掃描啟動類所在的包下所有的類 ,可以自定義不掃描某些 bean,如SpringBootApplication注解原始碼所示,容器中將排除TypeExcludeFilterh和AutoConfigurationExcludeFilter,
(2) EnableAutoConfiguration
啟用 SpringBoot 的自動配置機制
(3) Configuration
允許在背景關系中注冊額外的 bean 或匯入其他配置類
2.1 EnableAutoConfiguration詳解
@EnableAutoConfiguration是實作自動裝配的重要注解,在這個注解上存在以下兩個注解:AutoConfigurationPackage、Import,
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
2.1.1 AutoConfigurationPackage
表示對于標注該注解的類的包,應當使用
AutoConfigurationPackages注冊,實質上,它負責保存標注相關注解的類的所在包路徑,使用一個BasePackage類,保存這個路徑,然后使用@Import注解將其注入到ioc容器中,這樣,可以在容器中拿到該路徑,
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
}
查看
AutoConfigurationPackages中的Registrar這個類的原始碼,在Registrar#registerBeanDefinitions方法中有這樣一句代碼new PackageImport(metadata).getPackageName(),查看PackageImport的構造器后不難發現,這里獲取的是StandardAnnotationMetadata這個實體所在的包名,
/**
* metadata: 實際上是 StandardAnnotationMetadata 實體,
* metadata#getClassName(): 獲取標注 @AutoConfigurationPackage 注解的類的全限定名,
* ClassUtils.getPackageName(…): 獲取其所在包,
*/
PackageImport(AnnotationMetadata metadata) {
this.packageName = ClassUtils.getPackageName(metadata.getClassName());
}
此時再回去看
Registrar#registerBeanDefinitions中呼叫的AutoConfigurationPackages#register方法
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
// BEAN:AutoConfigurationPackages類的全限定名
// 此時判斷BeanDefinitionRegistry中是否存在以BEAN作為beanName的BeanDefinition物件
// 如果不存在,走else方法,構造了一個BackPackages實體,進行注冊
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition
.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0,
addBasePackages(constructorArguments, packageNames));
} else {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}
2.1.2 Import(AutoConfigurationImportSelector.class)
它是利用
AutoConfigurationImportSelector機制再來給容器中批量匯入一些配置東西的,接下來帶大家了解究竟匯入了哪些內容,
/**
* AutoConfigurationImportSelector類中存在一個叫selectImports的方法,就是我們到底要向容器中匯入哪些
* 內容,都會在這里進行掃描并匯入,
*/
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 判斷EnableAutoConfiguration是否開啟默認開啟true
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 1.加載META-INF/spring-autoconfigure-metadata.properties 檔案
// 2.從中獲取所有符合條件的支持自動裝配的類
// 自動配置類全名.條件=條件的值
AutoConfigurationMetadata autoConfigurationMetadata = https://www.cnblogs.com/jinsulive/p/AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 獲取AutoConfigurationEntry
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
接下來重點看
getAutoConfigurationEntry(annotationMetadata)方法,利用這個方法向容器中批量匯入一些默認支持自動配置的類,當你理解了這部分內容之后,就基本了解了Spring Boot是如何進行自動裝配的,廢話不多說,讓我們進入正題,
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 判斷EnableAutoConfiguration是否開啟默認開啟true
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 獲取注解屬性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 呼叫getCandidateConfigurations(annotationMetadata, attributes),利用loadSpringFactories(ClassLoader classLoader)加載當前系統所有的META-INF/spring.factories檔案,得到默認支持的自動配置的類的串列
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去除重復的 configuration
configurations = removeDuplicates(configurations);
// 獲取到SpringBootApplication上exclude和excludeName配置的需要排除的類
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 檢查configurations是否含有exclusions中的類
checkExcludedClasses(configurations, exclusions);
// 將exclusions中的類從configurations中排除
configurations.removeAll(exclusions);
// 對所有候選的自動配置類進行篩選,
// 比如ConditionalOnProperty 當屬性存在時
// ConditionalOnClass 當class存在
// ConditionalOnMissingClass 當這個clas不存在時才去配置
// 過濾器
configurations = getConfigurationClassFilter().filter(configurations);
// 將自動配置的類,匯入事件監聽器,并觸發fireAutoConfigurationImportEvents事件
// 加載META-INF\spring.factories中的AutoConfigurationImportListener
fireAutoConfigurationImportEvents(configurations, exclusions);
// 創建AutoConfigurationEntry物件
return new AutoConfigurationEntry(configurations, exclusions);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/508758.html
標籤:Java
上一篇:好書推薦之《JAVA編程思想》
