您好,登錄后才能下訂單哦!
這篇文章主要介紹“SpringBoot2入門自動(dòng)配置原理源碼分析”,在日常操作中,相信很多人在SpringBoot2入門自動(dòng)配置原理源碼分析問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”SpringBoot2入門自動(dòng)配置原理源碼分析”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!
之前為什么會(huì)去了解一些底層注解,其實(shí)就是為了后續(xù)更好的了解 springboot 底層的一些原理,比如自動(dòng)配置原理。
從 MainApplication 中的@SpringBootApplication
開始。
進(jìn)入@SpringBootApplication
,可以看到這是一個(gè)合成注解(紅框中是要關(guān)注的)。
這個(gè)注解干嘛的?
直接點(diǎn)進(jìn)去,發(fā)現(xiàn)有一個(gè)@Configuration
注解,那這不就是個(gè)配置類嘛。
進(jìn)而也說明了,MainApplication 也是一個(gè)配置類。
這個(gè)已經(jīng)很熟悉了,可以指定掃描哪些 Spring 注解。
只不過這里,加了一些其他的過濾條件,暫時(shí)不關(guān)注。
這個(gè)是最重要的注解了,聽名字就不一般,開啟自動(dòng)配置。
點(diǎn)進(jìn)去,發(fā)現(xiàn)也是一個(gè)合成注解(紅框需要關(guān)注)。
(1)@AutoConfigurationPackage
聽名字像是自動(dòng)配置包?依舊點(diǎn)進(jìn)去。
可以看到原來是導(dǎo)入了一個(gè)叫Registrar
的組件,繼續(xù)點(diǎn)進(jìn) Registrar
。
這里是利用Registrar()
給容器中導(dǎo)入一系列組件,也就是批量注冊(cè)組件。
在這里打個(gè)斷點(diǎn),debug 啟動(dòng)一下。
registerBeanDefinitions()
方法中有個(gè)傳參:
metadata
,是注解的元信息,可以看到這個(gè)注解是被標(biāo)注在com.pingguo.boot.MainApplication
。
而在registerBeanDefinitions()
方法體內(nèi),new 了一個(gè)AutoConfigurationPackages.PackageImports()
,里面?zhèn)魅氲氖窃⒔?,通過getPackageNames()
獲取到包名。
AutoConfigurationPackages.register( registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]) );
在 idea 中可以單獨(dú)執(zhí)行下片段代碼(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames()
。
選中右擊,再點(diǎn)擊 Evaluate。
得到的結(jié)果就是com.pingguo.boot
。為什么是這個(gè)?因?yàn)樽⒔鈽?biāo)注在MainApplication
類,而這個(gè)類就屬于com.pingguo.boot
。
拿到包名之后,封裝到數(shù)組里,也就是上述代碼片段中的toArray(new String[0])
,最后注冊(cè)進(jìn)去。
所以,這里的Registrar()
就是把指定的包下的所有組件批量注冊(cè)到容器中。
(2)@Import(AutoConfigurationImportSelector.class)
上面指定好默認(rèn)包規(guī)則之后,就需要去導(dǎo)入需要的包了,利用的是AutoConfigurationImportSelector
,繼續(xù)點(diǎn)進(jìn)去看。
這里有個(gè)selectImports
方法,這個(gè)方法決定了要具體導(dǎo)入哪些,返回的是一個(gè)數(shù)組。
方法體內(nèi),又是調(diào)用了getAutoConfigurationEntry()
方法來獲取配置入口,進(jìn)而再通過getConfigurations()
方法獲取具體配置,最終轉(zhuǎn)成數(shù)組返回。
顯然getAutoConfigurationEntry()
是個(gè)重點(diǎn)。
往下翻一點(diǎn),就是getAutoConfigurationEntry()
的實(shí)現(xiàn),在這里打個(gè)斷點(diǎn)(把上面的斷點(diǎn)取消掉)。
debug重新運(yùn)行一下,往下走到getCandidateConfigurations()
。
這里是獲取所有候選配置,目前可以看到這里是共有 127 個(gè)。
為什么是這 127 個(gè)?其實(shí)是在配置文件里寫死了,在 springboot 啟動(dòng)時(shí)候,給容器加載的所有場(chǎng)景的配置類。
定義的位置是在這:\spring-boot-autoconfigure\2.3.4.RELEASE\spring-boot-autoconfigure-2.3.4.RELEASE.jar!\META-INF\spring.factories
雖然這些一股腦的在啟動(dòng)時(shí)候會(huì)去加載到容器,但是最終會(huì)按需開啟配置。
比如點(diǎn)開aop
,看到@ConditionalOnClass({Advice.class})
這個(gè)條件,是當(dāng)存在Advice
類時(shí)候才導(dǎo)入組件,但實(shí)際上這里并沒有Advice
。
這就是基于 springboot 的按條件裝配@Conditional
,根據(jù)規(guī)則最終實(shí)現(xiàn)按需裝配。
分別用最終未生效、和生效的自動(dòng)配置來加深理解。
比如 cache。
可以看到CacheAutoConfiguration
上是加了幾個(gè)條件裝配的。
(1)@ConditionalOnClass({CacheManager.class})
在 idea 中使用ctrl+N
搜索一下CacheManager
,發(fā)現(xiàn)是存在的,那么這個(gè)條件滿足。
(2)@ConditionalOnBean({CacheAspectSupport.class})
這個(gè)條件是要求容器中存在CacheAspectSupport
這個(gè)組件才可以。
現(xiàn)在來判斷一下是否存在這個(gè)組件,在 main 方法里增加測(cè)試代碼:
... ... String[] beanNamesForType = run.getBeanNamesForType(CacheAspectSupport.class); System.out.println("==CacheAspectSupport類型組件的數(shù)量==" + beanNamesForType.length); ... ...
運(yùn)行查看輸出。
發(fā)現(xiàn)數(shù)量等于 0,也就是不存在該類型的組件。
也就是說@ConditionalOnBean({CacheAspectSupport.class})
這個(gè)條件不滿足,所以整個(gè)類CacheAutoConfiguration
里的配置都不生效。
之前寫過 web 的demo,那么 web 相關(guān)的配置自然是生效的,找到它。
這里有不少后綴是**AutoConfiguration
的配置,直接來看DispatcherServletAutoConfiguration
。
@Configuration(proxyBeanMethods = false)
:表示是一個(gè)配置類。
@ConditionalOnWebApplication(type = Type.SERVLET)
:條件是否為一個(gè) web 應(yīng)用,而且是原生 SERVLET 類型的(因?yàn)閟pringboot2還有webflux),當(dāng)前滿足條件。
@ConditionalOnClass({DispatcherServlet.class})
:條件是否導(dǎo)入了DispatcherServlet
類,這里也是有的。
還有 2 個(gè)注解直接沒見過,這里不用太多關(guān)注,了解一下:
@AutoConfigureOrder:這個(gè)配置類的配置優(yōu)先級(jí)順序。@AutoConfigureAfter:表示在xx之后才配置這個(gè)類,這里就是在配置完ServletWebServerFactoryAutoConfiguration.class
后,再配置當(dāng)前的類。
所以,類上的幾個(gè)條件都是滿足的,就可以進(jìn)一步到類中了,繼續(xù)往下找:
看到DispatcherServletConfiguration
類上也有條件:
@Conditional({DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition.class}):
別看這么長(zhǎng),其實(shí)就是上面的一個(gè)類
@ConditionalOnClass({ServletRegistration.class})
: 這個(gè)也存在。
@EnableConfigurationProperties({WebMvcProperties.class}):
這個(gè)很熟悉了,使用前面剛學(xué)習(xí)完不久,它并不是條件裝配,而是用來綁定外部配置文件的,點(diǎn)進(jìn)去。
可以看到,會(huì)與配置文件中前綴是spring.mvc
的所有屬性進(jìn)行綁定。
另外,還可以自動(dòng)把組件注冊(cè)到容器中去。
這里可以試一下,在 main 方法里增加輸出:
String[] beanNamesForType1 = run.getBeanNamesForType(WebMvcProperties.class); System.out.println("==WebMvcProperties類型組件的數(shù)量==" + beanNamesForType1.length);
運(yùn)行一下,果然是有一個(gè):
到此,說明DispatcherServletConfiguration
這個(gè)配置類也是生效的。
繼續(xù)往下就看到方法dispatcherServlet()
,而且是加了@Bean
注解,就是給容器中注冊(cè)DispatcherServlet
類型的組件。
這里的經(jīng)過是:
new 一個(gè)DispatcherServlet()
對(duì)象dispatcherServlet
。接著對(duì)dispatcherServlet
一通 set 設(shè)置。最后返回這個(gè)對(duì)象dispatcherServlet
。
在之前學(xué)習(xí) springMVC 時(shí)候,還要手動(dòng)去設(shè)置關(guān)于DispatcherServlet
的一堆東西。而在 springboot 里已經(jīng)在底層設(shè)置好了,并且注冊(cè)到容器中去了,所以我們能直接使用。
到此,關(guān)于“SpringBoot2入門自動(dòng)配置原理源碼分析”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。