如何通過一張圖搞懂springBoot自動注入原理
@SpringBootApplication注解解讀
為什么我們的啟動類上標注一個@SpringBootApplication注解,再加一個run()方法就可運行起來,可以看出我們的@SpringBootApplication注解是多么的強大。
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
@SpringBootApplication其實是由三個字注解來合成的。我們可以完全用這個三個注解來替換掉@SpringBootApplication。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
我們來說下這三個注解的一個作用,分別做了什么事情,為什么區(qū)區(qū)幾個注解就可以讓我們的程序跑起來。
1.@SpringBootConfiguration
其實點擊進去就是一個 @Configuration,沒什么特別的,學(xué)習(xí)過spring的朋友都知道,這是用于標注一個配置類的。
2.@EnableAutoConfiguration
重點就是在于@EnableAutoConfiguration 這個注解,我們先看下他的一個構(gòu)成。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@Inherited
@Inherited : 如果標注此注解標識子類也可以進行繼承,這個不太重要
我們先來看.@EnableAutoConfiguration 注解中的@AutoConfigurationPackage注解里面的內(nèi)容有什么 ? 可以看到導(dǎo)入了一個AutoConfigurationPackages.Registrar類型的組件
@AutoConfigurationPackage
@AutoConfigurationPackage:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
我們來看下導(dǎo)入的這個AutoConfigurationPackages.Registrar組件做了什么事情?
registerBeanDefinitions? registerBeanDefinitions是不是就是往我們的容器中添加組件?。磕俏覀儊砜纯此唧w導(dǎo)入了那些組件。你可以將斷點打在這兩個方法上
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}

只要把BeanDefinition注冊進去,往后我們只要調(diào)用getBean()就會得到該對象,當(dāng)然不一定得我們自己調(diào)用,spring在底層最后刷新容器的時候,就會初始化所有的單實例bean,這也就是為什么我們直接使用相關(guān)注解就可以獲取到該對象的原有。
getBean()有兩層意思:
1.容器中有直接從緩存中獲取
2.容器中沒有直接創(chuàng)建一個,也就是走bean的生命周期創(chuàng)建
AutoConfigurationImportSelector.class
@Import(AutoConfigurationImportSelector.class) 核心組件,我們來看看他做了什么事情。
AutoConfigurationImportSelector他呢繼承了DeferredImportSelector,DeferredImportSelector他呢有個內(nèi)部接口Group,而Group中又有個方法process()
所以我們來到AutoConfigurationImportSelector中的process()方法打上斷點進行觀察
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
這個方法一上來就要獲取一些自動注入的條目autoConfigurationEntry,那我們看下他是怎么獲取的,獲取的究竟是什么東西?
通過堆棧信息我們可以看到是通過invokeBeanDefinitionRegistryPostProcessors()這個方法調(diào)用過來的,說明在工廠初始化完畢,你可以往里面仍一些bean的定義信息了。
進去就是這個方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
我們再進入這個方法

在進入loadFactoryNames()方法中

那我們?nèi)タ纯催@個文件里面有什么

結(jié)合上面的代碼他是不是要加載org.springframework.boot.autoconfigure.EnableAutoConfiguration里面的內(nèi)容,這些就是一些配置類的信息
其實這個文件 spring.factories 里面的每一個類的權(quán)限的名稱就是一個配置類,只不過springBoot把這些配置類都寫好了,在我們某些場景需要的時候直接給你注入就行,這就說明了我們不用寫那么多配置文件的原因。
我隨便點擊一個類進去看看

加載完成后: 怎么多?是不是全部第用得上?。?/p>

你看下面的代碼,是不是要排除,移除掉,過濾掉一些啊,排除就是我們自己在注解中寫的排除屬性進行排除,讓后就是經(jīng)過一系列的篩選過濾。

最后將這些信息put到entries中


3.@ComponentScan
@ComponentScan這個注解的功能就是掃描當(dāng)前類上標注此注解所在包路徑的所有類,這也就是為什么我們需要把主啟動類放在最外面的原有,如果你想把配置類放在別的地方,那你就得自己手動指定包掃描路徑.
最后奉上超清晰的圖

總結(jié)
到此這篇關(guān)于如何通過一張圖搞懂springBoot自動注入原理的文章就介紹到這了,更多相關(guān)springBoot自動注入原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java DriverManager.getConnection()獲取數(shù)據(jù)庫連接
這篇文章主要介紹了Java DriverManager.getConnection()獲取數(shù)據(jù)庫連接,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01

