0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

SpingBoot的5個(gè)擴(kuò)展點(diǎn),超級(jí)實(shí)用!

jf_ro2CN3Fa ? 來源:稀土掘金 ? 2024-02-22 11:28 ? 次閱讀

1、初始化器ApplicationContextInitializer

我們?cè)趩?dòng)Spring Boot項(xiàng)目的時(shí)候,是執(zhí)行這樣一個(gè)方法來啟動(dòng)的

abd0c146-d123-11ee-a297-92fbcf53809c.jpg

我們一層一層往下點(diǎn),最終發(fā)現(xiàn)執(zhí)行的是這個(gè)方法

abdef072-d123-11ee-a297-92fbcf53809c.jpg

所以我們?cè)趩?dòng)項(xiàng)目的時(shí)候也可以這樣啟動(dòng) new SpringApplication(SpringbootExtensionPointApplication.class).run(args); 老的只是包裝了一個(gè)靜態(tài)方法,實(shí)際底層就是實(shí)例化一個(gè)SpringApplication對(duì)象,然后調(diào)用它的run方法。

abe7e056-d123-11ee-a297-92fbcf53809c.jpg

我們進(jìn)到構(gòu)造方法里看下,紅框里面標(biāo)出來的,一個(gè)是設(shè)置初始化器,一個(gè)是設(shè)置監(jiān)聽器。

abedae28-d123-11ee-a297-92fbcf53809c.jpg

點(diǎn)進(jìn)去看下,這兩個(gè)底層調(diào)的方法是一樣,就是傳入一個(gè)類型,通過Spring SPI的方式查找這個(gè)類型的實(shí)現(xiàn)類

abfd4086-d123-11ee-a297-92fbcf53809c.jpg

打個(gè)斷點(diǎn),啟動(dòng)一下,此時(shí)有7個(gè)上下文初始器,這是系統(tǒng)自帶的,配置在不同的spring.factories文件中。

ac04d81e-d123-11ee-a297-92fbcf53809c.jpg

現(xiàn)在我要新建一個(gè)自己的初始化器

ac15ab80-d123-11ee-a297-92fbcf53809c.jpg

此時(shí)為了能夠讓Spring Boot在啟動(dòng)的時(shí)候能夠掃描到我創(chuàng)建的初始化器應(yīng)該怎么辦?就是在spring.factories文件中添加一下,注冊(cè)一下,這樣就能掃描到,這個(gè)就是SPI。SPI 全稱為 Service Provider Interface,是一種服務(wù)發(fā)現(xiàn)機(jī)制。

ac22d224-d123-11ee-a297-92fbcf53809c.jpg

那么這時(shí)候我們?cè)賳?dòng)一下Spring Boot,發(fā)現(xiàn)自己創(chuàng)建的ApplicationContextInitializer也已經(jīng)注冊(cè)上來了,變成8個(gè)了。

ac3169e2-d123-11ee-a297-92fbcf53809c.jpg

把斷點(diǎn)放掉,在控制臺(tái)中也打印出了這句話,那么這個(gè)就是第一個(gè)擴(kuò)展點(diǎn)ApplicationContextInitializer

ac38b526-d123-11ee-a297-92fbcf53809c.jpg

定義了這8個(gè)初始化器,那一定是有地方在調(diào)它們的,不然怎么會(huì)打印出來呢,那具體在什么地方調(diào)的,我們?cè)谧约旱某跏蓟鞯牡胤酱驍帱c(diǎn),看到已經(jīng)進(jìn)來了,然后看下方的堆棧信息,這個(gè)就是調(diào)用的地方。

ac439fea-d123-11ee-a297-92fbcf53809c.jpg

原來是調(diào)用了run()方法中的prepareContext()方法中的applyInitializers()方法,在這個(gè)方法中for循環(huán)的調(diào)用各個(gè)初始化器的initialize()方法,從而我們就能看到把Jack的ApplicationContextInitializer這句話給打印出來了。

那么這個(gè)查找的方法就是以結(jié)果為導(dǎo)向來反查調(diào)用方,因?yàn)槟阏榈脑捠呛茈y找到,很難記住的,這個(gè)方法希望大家學(xué)習(xí)到。

ac4d959a-d123-11ee-a297-92fbcf53809c.jpg

那么最后來看下我們第一個(gè)擴(kuò)展點(diǎn)所處的位置

ac5326b8-d123-11ee-a297-92fbcf53809c.jpg

初始化器可以做一些事情,比如Environment對(duì)象設(shè)置一些變量配置。

2、監(jiān)聽器ApplicationListener

在上面構(gòu)造函數(shù)里我們發(fā)現(xiàn)除了有setInitializers,還有setListeners,那么這個(gè)listeners其實(shí)也是一個(gè)擴(kuò)展點(diǎn)。

ac6006da-d123-11ee-a297-92fbcf53809c.jpg

那么什么是監(jiān)聽器,就是這樣的,這個(gè)其實(shí)就是觀察者模式,ApplicationEventMulticaster發(fā)布事件,各個(gè)Listener監(jiān)聽事件。

ac6a9636-d123-11ee-a297-92fbcf53809c.jpg

和初始化器一樣,現(xiàn)在我們自定義兩個(gè)監(jiān)聽器,一個(gè)是Starting,一個(gè)是Started,括號(hào)里面的是泛型,這個(gè)是一定要寫的,如果不寫的話就是不管什么類型的Event都會(huì)監(jiān)聽。

ac7064c6-d123-11ee-a297-92fbcf53809c.jpgac7d6036-d123-11ee-a297-92fbcf53809c.jpg

這個(gè)泛型是上限為ApplicationEvent類型的Event,具體的實(shí)現(xiàn)類有很多個(gè),Starting和Started只是其中兩個(gè)。

ac886bde-d123-11ee-a297-92fbcf53809c.jpgac915ce4-d123-11ee-a297-92fbcf53809c.jpg

現(xiàn)在我們還是把這兩個(gè)監(jiān)聽器通過SPI的方式加到配置中去

ac9c31fa-d123-11ee-a297-92fbcf53809c.jpg

好,運(yùn)行一下,我們看到這兩句話已經(jīng)打印出來了

aca3689e-d123-11ee-a297-92fbcf53809c.jpg

和監(jiān)聽器一樣,既然能夠打印出來,那肯定是有地方在調(diào)用,所以我們?cè)贘ackStartingApplicationListener打個(gè)斷點(diǎn),然后看下堆棧信息

aca7ecd4-d123-11ee-a297-92fbcf53809c.jpg

我們可以看到在SpringApplication run()方法的listeners.starting()開始進(jìn)去發(fā)送ApplicationStartingEvent廣播事件,最后發(fā)布出去,由我們自己編寫的事件監(jiān)聽器接收到。

acb37180-d123-11ee-a297-92fbcf53809c.jpgacb9465a-d123-11ee-a297-92fbcf53809c.jpg

那么ApplicationStartedEvent事件也是一樣的道理,通過打斷點(diǎn)的方式來找到它的調(diào)用方,最后我們?cè)賮砜聪麓藭r(shí)的擴(kuò)展點(diǎn)圖

acc19bca-d123-11ee-a297-92fbcf53809c.jpg

3、Runner

我們看到在listeners.started()后面有個(gè)callRunners

acc56958-d123-11ee-a297-92fbcf53809c.jpg

我們點(diǎn)進(jìn)去看下,它其實(shí)就是從容器中獲取兩種類型的Runner,一種是ApplicationRunner,還有一種是CommandLineRunner,然后for循環(huán)的對(duì)它們進(jìn)行調(diào)用,那么其實(shí)這個(gè)也是一個(gè)擴(kuò)展點(diǎn)

acccb172-d123-11ee-a297-92fbcf53809c.jpg

我們來寫一個(gè)自己的Runner

acd64336-d123-11ee-a297-92fbcf53809c.jpg

運(yùn)行一下,看下打印出來了

ace1cfb2-d123-11ee-a297-92fbcf53809c.jpg

那么這個(gè)Runner的一般應(yīng)用場(chǎng)景就是資源釋放清理或者做注冊(cè)中心,因?yàn)閳?zhí)行到Runner的時(shí)候項(xiàng)目已經(jīng)啟動(dòng)完畢了,這時(shí)候就可以注冊(cè)到注冊(cè)中心上去了。此時(shí)我們?cè)倏聪聰U(kuò)展點(diǎn)圖。

ace77fc0-d123-11ee-a297-92fbcf53809c.jpg

4、BeanFactoryPostProcessor

我們看下run方法里的refreshContext()方法

aceb7364-d123-11ee-a297-92fbcf53809c.jpg

這個(gè)方法底層會(huì)調(diào)spring里面的refresh()方法,這個(gè)方法里面就會(huì)做對(duì)容器的初始化。紅框里的invokeBeanFactoryPostProcessors()方法,這里也有一個(gè)擴(kuò)展點(diǎn),就是BeanFactoryPostProcessor,執(zhí)行對(duì)BeanFactory的后置處理。Spring Boot解析配置成BeanDefinition的操作也是在此方法中。

acf5f276-d123-11ee-a297-92fbcf53809c.jpg

現(xiàn)在我們來創(chuàng)建一個(gè)自己的BeanFactoryPostProcessor,這個(gè)方法里面可以修改beanFactory的屬性,beanfactory里面有BeanDefinition,可以修改BeanDefinition里面的值。BeanDefinition是一個(gè)bean的元數(shù)據(jù)的信息,有多少個(gè)bean就有多少個(gè)BeanDefinition。

acfe89ea-d123-11ee-a297-92fbcf53809c.jpg

運(yùn)行一下,也打印出來了

ad02683a-d123-11ee-a297-92fbcf53809c.jpg

此時(shí)我們?cè)倏聪聰U(kuò)展點(diǎn)圖,越來越完善了。

ad0d88be-d123-11ee-a297-92fbcf53809c.jpg

5、BeanPostProcessor

最后介紹的是BeanPostProcessor,它在通過反射構(gòu)造函數(shù)進(jìn)行bean實(shí)例化之后執(zhí)行,那么紅框里面標(biāo)出來的registerBeanPostProcessors()方法就是向BeanFactory中注冊(cè)beanpostprocessor,用于后續(xù)bean創(chuàng)建的攔截操作。

ad202c9e-d123-11ee-a297-92fbcf53809c.jpg

現(xiàn)在我們來創(chuàng)建一個(gè)自己的BeanPostProcessor,一共有兩個(gè)方法,postProcessBeforeInitialization和postProcessAfterInitialization,不過我們一般用postProcessAfterInitialization,在bean調(diào)用反射構(gòu)造函數(shù)實(shí)例化之后執(zhí)行。著名的應(yīng)用場(chǎng)景AOP底層就是通過BeanPostProcessor來實(shí)現(xiàn)的。

ad26b26c-d123-11ee-a297-92fbcf53809c.jpg

現(xiàn)在我在postProcessAfterInitialization上打個(gè)斷點(diǎn),看下堆棧信息是在哪里調(diào)用的

ad31e42a-d123-11ee-a297-92fbcf53809c.jpg

是在finishBeanFactoryInitialization()方法處調(diào)用的

ad37d4ac-d123-11ee-a297-92fbcf53809c.jpg

后記

最后我來把擴(kuò)展點(diǎn)圖補(bǔ)充完整,如下所示,很清晰明了,在什么時(shí)候調(diào)用了什么,我們自己開發(fā)的時(shí)候結(jié)合應(yīng)用場(chǎng)景,在什么時(shí)候要干什么事,就知道要?jiǎng)?chuàng)建什么類型的擴(kuò)展點(diǎn)了。

ad458c5a-d123-11ee-a297-92fbcf53809c.jpg

本文前三個(gè)講的是Spring Boot里面自己有的擴(kuò)展點(diǎn),后兩個(gè)因?yàn)镾pring Boot底層調(diào)的是Spring的源碼,所以屬于Spring里面的擴(kuò)展點(diǎn),所以如果這么算的話Spring里面的擴(kuò)展點(diǎn)還有很多擴(kuò)展點(diǎn),比如InitializeBean、Aware等等這里都沒講,等待大家去發(fā)掘,謝謝觀看 ~




審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • AOP
    AOP
    +關(guān)注

    關(guān)注

    0

    文章

    40

    瀏覽量

    11070
  • for循環(huán)
    +關(guān)注

    關(guān)注

    0

    文章

    61

    瀏覽量

    2471

原文標(biāo)題:SpingBoot的5個(gè)擴(kuò)展點(diǎn),超級(jí)實(shí)用!

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    超級(jí)電容電源模組

    本帖最后由 544642572 于 2013-8-28 10:15 編輯 最近對(duì)超級(jí)電容很感興趣,想設(shè)計(jì)一個(gè)超級(jí)電容充放電的電路,于是買了5個(gè)
    發(fā)表于 08-27 10:27

    bW6101-超級(jí)法拉電容過壓保護(hù)芯片

    。 可以通過外部端口選擇為兩種規(guī)格的超級(jí)電容進(jìn)行充電保護(hù)。當(dāng)選擇端口為高電平時(shí),對(duì)應(yīng)保護(hù)點(diǎn)為2.65V,當(dāng)選擇端口電平為低時(shí),對(duì)應(yīng)保護(hù)點(diǎn)為2.45V。方便用戶的靈活使用。 采用小型化的SOT23-
    發(fā)表于 12-24 14:44

    超級(jí)電容保護(hù)芯片-BW6101

    。 可以通過外部端口選擇為兩種規(guī)格的超級(jí)電容進(jìn)行充電保護(hù)。當(dāng)選擇端口為高電平時(shí),對(duì)應(yīng)保護(hù)點(diǎn)為2.65V,當(dāng)選擇端口電平為低時(shí),對(duì)應(yīng)保護(hù)點(diǎn)為2.45V。方便用戶的靈活使用。 采用小型化的SOT23-
    發(fā)表于 01-09 13:50

    超級(jí)電容器充電

    5v/500mA電源給超級(jí)電容器充電,超級(jí)電容器要怎么選擇?我在這方面完全小白,之前沒接觸過超級(jí)電容器的充電。目的就是做一個(gè)
    發(fā)表于 06-03 14:41

    基于FPGA的超級(jí)電容均壓及充放電設(shè)計(jì)方案

    :Vc為N個(gè)串聯(lián)超級(jí)電容兩端總電壓;Vd為續(xù)流二極管上的正向?qū)▔航?;Vs為MOSFET上的導(dǎo)通壓降?! ∧孀儾糠植捎?b class='flag-5'>5kHz的50%占空比的PWM波加入一定的死區(qū)時(shí)間來實(shí)現(xiàn),S1,S4采用同一組信號(hào)
    發(fā)表于 12-03 11:01

    超級(jí)電容容量選取

    超級(jí)電容驅(qū)動(dòng)LED燈組,1500mA 8個(gè)并聯(lián),正向壓降3.1V 超級(jí)電容 放電12A 放電時(shí)間10mS 超級(jí)電容充滿電壓5V 求
    發(fā)表于 07-03 05:55

    個(gè)提供標(biāo)準(zhǔn)擴(kuò)展點(diǎn)的javascript小部件

    我有一個(gè)提供標(biāo)準(zhǔn)擴(kuò)展點(diǎn)的javascript小部件。其中之一是beforecreate函數(shù)。它應(yīng)該返回false以防止創(chuàng)建項(xiàng)目。我已經(jīng)使用jquery向這個(gè)函數(shù)添加了一個(gè)Ajax調(diào)用
    發(fā)表于 09-06 07:12

    模擬/數(shù)字點(diǎn)擴(kuò)展模塊

    點(diǎn)擴(kuò)展模塊(Point Expansion Modules)為控制和檢測(cè)遠(yuǎn)距離的點(diǎn)提供了低成本的解決方案。作為現(xiàn)場(chǎng)控制器的延伸,點(diǎn)擴(kuò)展模塊的
    發(fā)表于 03-30 16:29 ?21次下載

    紫光5G超級(jí)SIM卡開售,支持存儲(chǔ)功能和SIM通信功能

    紫光5G超級(jí)SIM卡今日10點(diǎn)在廣州聯(lián)通新時(shí)空營(yíng)業(yè)廳開賣,官方表示紫光5G超級(jí)SIM卡適配nano+nano/儲(chǔ)存復(fù)合卡槽,適配終端包括華為
    的頭像 發(fā)表于 12-23 14:09 ?4145次閱讀

    紫光與聯(lián)通的5G超級(jí)SIM卡可支持存儲(chǔ)功能

    紫光國(guó)微與廣東聯(lián)通將于今日10點(diǎn)在廣東聯(lián)通新時(shí)空營(yíng)業(yè)廳發(fā)布5G超級(jí)SIM卡。這種5G超級(jí)SIM卡以同時(shí)支持存儲(chǔ)功能和通信功能為特點(diǎn),將有效緩
    的頭像 發(fā)表于 12-23 14:34 ?3503次閱讀

    特斯拉11月已開放517個(gè)超級(jí)充電樁

    日前,特斯拉官方表示,特斯拉11月在全國(guó)37座城市共開放了60座特斯拉超級(jí)充電站,共計(jì)517個(gè)超級(jí)充電樁。目前,特斯拉在全球范圍內(nèi)擁有超過2萬個(gè)超級(jí)
    的頭像 發(fā)表于 12-15 17:30 ?2391次閱讀

    Arduino 32點(diǎn)IO擴(kuò)展板開源項(xiàng)目

    電子發(fā)燒友網(wǎng)站提供《Arduino 32點(diǎn)IO擴(kuò)展板開源項(xiàng)目.zip》資料免費(fèi)下載
    發(fā)表于 07-18 10:47 ?4次下載
    Arduino 32<b class='flag-5'>點(diǎn)</b>IO<b class='flag-5'>擴(kuò)展</b>板開源項(xiàng)目

    為什么說 GaN 是 5G 的超級(jí)“動(dòng)力”

    為什么說 GaN 是 5G 的超級(jí)“動(dòng)力”
    的頭像 發(fā)表于 12-26 10:16 ?1341次閱讀
    為什么說 GaN 是 <b class='flag-5'>5</b>G 的<b class='flag-5'>超級(jí)</b>“動(dòng)力”

    Spring中11個(gè)最常用的擴(kuò)展點(diǎn)分享1

    在使用spring的過程中,我們有沒有發(fā)現(xiàn)它的擴(kuò)展能力很強(qiáng)呢?由于這個(gè)優(yōu)勢(shì)的存在,使得spring具有很強(qiáng)的包容性,所以很多第三方應(yīng)用或者框架可以很容易的投入到spring的懷抱中。今天我們主要來學(xué)習(xí)Spring中很常用的11個(gè)擴(kuò)展
    的頭像 發(fā)表于 05-11 10:48 ?479次閱讀

    Spring中11個(gè)最常用的擴(kuò)展點(diǎn)分享2

    在使用spring的過程中,我們有沒有發(fā)現(xiàn)它的擴(kuò)展能力很強(qiáng)呢?由于這個(gè)優(yōu)勢(shì)的存在,使得spring具有很強(qiáng)的包容性,所以很多第三方應(yīng)用或者框架可以很容易的投入到spring的懷抱中。今天我們主要來學(xué)習(xí)Spring中很常用的11個(gè)擴(kuò)展
    的頭像 發(fā)表于 05-11 10:48 ?325次閱讀