欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot2入門自動(dòng)配置原理及源碼分析

 更新時(shí)間:2022年05月27日 16:56:09   作者:把蘋果咬哭的測(cè)試筆記  
這篇文章主要為大家介紹了SpringBoot2入門自動(dòng)配置原理及源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

SpringBoot自動(dòng)配置

之前為什么會(huì)去了解一些底層注解,其實(shí)就是為了后續(xù)更好的了解 springboot 底層的一些原理,比如自動(dòng)配置原理。

一、@SpringBootApplication

從 MainApplication 中的@SpringBootApplication開(kāi)始。

進(jìn)入@SpringBootApplication,可以看到這是一個(gè)合成注解(紅框中是要關(guān)注的)。

1. @SpringBootConfiguration

這個(gè)注解干嘛的?

直接點(diǎn)進(jìn)去,發(fā)現(xiàn)有一個(gè)@Configuration注解,那這不就是個(gè)配置類嘛。

進(jìn)而也說(shuō)明了,MainApplication 也是一個(gè)配置類。

2. @ComponentScan

這個(gè)已經(jīng)很熟悉了,可以指定掃描哪些 Spring 注解。

只不過(guò)這里,加了一些其他的過(guò)濾條件,暫時(shí)不關(guān)注。

3. @EnableAutoConfiguration

這個(gè)是最重要的注解了,聽(tīng)名字就不一般,開(kāi)啟自動(dòng)配置。

點(diǎn)進(jìn)去,發(fā)現(xiàn)也是一個(gè)合成注解(紅框需要關(guān)注)。

(1)@AutoConfigurationPackage

聽(tīng)名字像是自動(dòng)配置包?依舊點(diǎn)進(jìn)去。

可以看到原來(lái)是導(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)魅氲氖窃⒔?,通過(guò)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()方法來(lái)獲取配置入口,進(jìn)而再通過(guò)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ì)按需開(kāi)啟配置。

比如點(diǎn)開(kāi)aop,看到@ConditionalOnClass({Advice.class})這個(gè)條件,是當(dāng)存在Advice類時(shí)候才導(dǎo)入組件,但實(shí)際上這里并沒(méi)有Advice。

這就是基于 springboot 的按條件裝配@Conditional,根據(jù)規(guī)則最終實(shí)現(xiàn)按需裝配。

二、自動(dòng)配置示例

分別用最終未生效、和生效的自動(dòng)配置來(lái)加深理解。

1. 未生效的自動(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)在來(lái)判斷一下是否存在這個(gè)組件,在 main 方法里增加測(cè)試代碼:

... ...
      String[] beanNamesForType = run.getBeanNamesForType(CacheAspectSupport.class);
      System.out.println("==CacheAspectSupport類型組件的數(shù)量==" + beanNamesForType.length);
... ...

運(yùn)行查看輸出。

發(fā)現(xiàn)數(shù)量等于 0,也就是不存在該類型的組件。

也就是說(shuō)@ConditionalOnBean({CacheAspectSupport.class})這個(gè)條件不滿足,所以整個(gè)類CacheAutoConfiguration里的配置都不生效。

2. 生效的自動(dòng)配置

之前寫過(guò) web 的demo,那么 web 相關(guān)的配置自然是生效的,找到它。

這里有不少后綴是**AutoConfiguration的配置,直接來(lái)看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è)注解直接沒(méi)見(jiàn)過(guò),這里不用太多關(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í)完不久,它并不是條件裝配,而是用來(lái)綁定外部配置文件的,點(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è):

到此,說(shuō)明DispatcherServletConfiguration這個(gè)配置類也是生效的。

繼續(xù)往下就看到方法dispatcherServlet(),而且是加了@Bean注解,就是給容器中注冊(cè)DispatcherServlet類型的組件。

這里的經(jīng)過(guò)是:

  • 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è)到容器中去了,所以我們能直接使用。

三、小結(jié)

隨著進(jìn)一步跟著源碼來(lái)理解自動(dòng)配置的原理,使得自己更深的體會(huì)到 springboot 的優(yōu)點(diǎn)。

那么多東西不需要我們手動(dòng)去配置了,并不是說(shuō)用不上,而是在底層springboot已經(jīng)幫我們完成好了配置。

當(dāng)然,目前的重點(diǎn)還是學(xué)會(huì)使用 springboot,但是帶著之前對(duì) springboot 的疑問(wèn)來(lái)學(xué)習(xí),還是更有收獲的。

以上就是SpringBoot2入門自動(dòng)配置原理及源碼分析的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot2自動(dòng)配置的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java基礎(chǔ)教程之接口的繼承與抽象類

    Java基礎(chǔ)教程之接口的繼承與抽象類

    這篇文章主要介紹了Java基礎(chǔ)教程之接口的繼承與抽象類,本文介紹了接口繼承、接口的多重繼承以及抽象類的知識(shí),需要的朋友可以參考下
    2014-09-09
  • Java對(duì)接ansible自動(dòng)運(yùn)維化平臺(tái)方式

    Java對(duì)接ansible自動(dòng)運(yùn)維化平臺(tái)方式

    這篇文章主要介紹了Java對(duì)接ansible自動(dòng)運(yùn)維化平臺(tái)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Java微信公眾號(hào)開(kāi)發(fā)之通過(guò)微信公眾號(hào)獲取用戶信息

    Java微信公眾號(hào)開(kāi)發(fā)之通過(guò)微信公眾號(hào)獲取用戶信息

    這篇文章主要介紹了Java微信公眾號(hào)開(kāi)發(fā)之通過(guò)微信公眾號(hào)獲取用戶信息,需要的朋友可以參考下
    2017-05-05
  • Java枚舉學(xué)習(xí)之定義和基本特性詳解

    Java枚舉學(xué)習(xí)之定義和基本特性詳解

    枚舉是JAVA?5.0后增加的一個(gè)重要類型??梢杂脕?lái)表示一組取值范圍固定的變量。本文將通過(guò)示例為大家詳細(xì)講解枚舉的定義和基本特性,感興趣的可以了解一下
    2022-08-08
  • SpringCloud Netflix Ribbon源碼解析(推薦)

    SpringCloud Netflix Ribbon源碼解析(推薦)

    這篇文章主要介紹了SpringCloud Netflix Ribbon源碼解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • Java 泛型 Generic機(jī)制實(shí)例詳解

    Java 泛型 Generic機(jī)制實(shí)例詳解

    這篇文章主要為大家介紹了Java 泛型 Generic機(jī)制實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Mac下設(shè)置Java默認(rèn)版本的方法

    Mac下設(shè)置Java默認(rèn)版本的方法

    今天工作的時(shí)候發(fā)現(xiàn)了一個(gè)錯(cuò)誤,提示java版本太低,無(wú)法啟動(dòng)!想起自己裝過(guò)高版本的Java,但是卻沒(méi)有默認(rèn)啟動(dòng),從網(wǎng)上找了一些資料,整理下現(xiàn)在分享給大家,有需要的可以參考借鑒。
    2016-10-10
  • idea中MavenWeb項(xiàng)目不能創(chuàng)建Servlet的解決方案

    idea中MavenWeb項(xiàng)目不能創(chuàng)建Servlet的解決方案

    這篇文章主要介紹了idea中MavenWeb項(xiàng)目不能創(chuàng)建Servlet的解決方案,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java詳解對(duì)象終止方法finalize()的用法

    Java詳解對(duì)象終止方法finalize()的用法

    在前面的 jvm 中, 需要補(bǔ)充幾個(gè)部分的內(nèi)容, 接著來(lái)看 finalize() 機(jī)制, 它可以使接近死亡的對(duì)象復(fù)活, 下來(lái)我們來(lái)看是怎么一回事
    2022-05-05
  • java線程并發(fā)cyclicbarrier類使用示例

    java線程并發(fā)cyclicbarrier類使用示例

    CyclicBarrier類似于CountDownLatch也是個(gè)計(jì)數(shù)器,不同的是CyclicBarrier數(shù)的是調(diào)用了CyclicBarrier.await()進(jìn)入等待的線程數(shù),當(dāng)線程數(shù)達(dá)到了CyclicBarrier初始時(shí)規(guī)定的數(shù)目時(shí),所有進(jìn)入等待狀態(tài)的線程被喚醒并繼續(xù),下面使用示例學(xué)習(xí)他的使用方法
    2014-01-01

最新評(píng)論