Spring之事件機(jī)制初始化流程

描述

在Spring之事件機(jī)制模型中我們了解了spring事件機(jī)制的模型以及工作流程,下面通過(guò)源碼分析spring事件機(jī)制的初始化流程

在工作流程中兜粘,可以看到事件發(fā)布者ApplicationEventPublisher 發(fā)布事件是通過(guò)事件廣播中心ApplicationEventMulticaster 將事件event通知到具體的事件監(jiān)聽(tīng)器ApplicationListener 那么初始化流程應(yīng)該有如下幾步:

  1. 給事件發(fā)布者ApplicationEventPublisher 設(shè)置ApplicationEventMulticaster并初始化
  2. 注冊(cè)事件監(jiān)聽(tīng)器到事件ApplicationEventMulticaster
  3. 事件發(fā)布時(shí)萍桌,通過(guò)ApplicationEventMulticaster通知事件監(jiān)聽(tīng)器柠掂。

初始化入口

// 類 AbstractApplicationContext
  public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            //容器刷新前的處理方法
            prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            //使用容器前beanFactory的前置處理方法
            prepareBeanFactory(beanFactory)
            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                //在容器中執(zhí)行bean工廠后置處理器
                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                //初始化容器的事件廣播器
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // 注冊(cè)事件監(jiān)聽(tīng)器到事件廣播器中
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);
            }
            catch (BeansException ex) {
                throw ex;
            }
        }
    }

ApplicaitonContext 繼承事件發(fā)布者接口熊杨,在ApplicaitonContext的refresh方法中完成了事件機(jī)制初始化的流程,如下:

  1. 初始化發(fā)布者即容器的事件廣播中心ApplicationEventMulticaster
    //初始化容器的事件廣播器
    initApplicationEventMulticaster();
  1. 注冊(cè)事件監(jiān)聽(tīng)器到事件廣播中心
        // 注冊(cè)事件監(jiān)聽(tīng)器到事件廣播器中
        registerListeners();

initApplicationEventMulticaster

    /**
     * 初始化當(dāng)前容器發(fā)布者持有的事件廣播中心實(shí)例
     */
    protected void initApplicationEventMulticaster() {
        //獲取beanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //判斷beanFactory中是否存在事件廣播中心bean實(shí)例
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            //存在時(shí)别垮,beanFactory中的事件廣播中心bean實(shí)例賦值給applicationEventMulticaster
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        }
        else {
            //不能存在挑胸,new 創(chuàng)建新的applicationEventMulticaster并賦值給applicationEventMulticaster
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            //將創(chuàng)建的新事件廣播中心bean實(shí)例注冊(cè)到單例bean注冊(cè)中心
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        }
    }

initApplicationEventMulticaster 方法主要功能是創(chuàng)建事件廣播中心實(shí)例,創(chuàng)建的方式:

  • beanFactory 已經(jīng)存在實(shí)例 宰闰,通過(guò)beanFactory獲取已經(jīng)存在的實(shí)例賦值給當(dāng)前發(fā)布者
  • 不存在茬贵,通過(guò)new 關(guān)鍵字創(chuàng)建實(shí)例,賦值給發(fā)布者移袍,并將當(dāng)前實(shí)例注冊(cè)到單例注冊(cè)中心

registerListeners

    protected void registerListeners() {
        // 注冊(cè)靜態(tài)指定的事件監(jiān)聽(tīng)器ApplicationListener到事件廣播中心ApplicationEventMulticaster
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        // 在beanFactory中查找ApplicationListener名稱集合
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            //遍歷名稱并將當(dāng)前名稱的事件監(jiān)聽(tīng)器注冊(cè)到事件廣播中心
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        //所有事件監(jiān)聽(tīng)器添加完成后解藻,遍歷發(fā)布者(ApplicationEventPublisher-ApplicaitonContext)已經(jīng)發(fā)布的事件集合,并將事件通知到給定的監(jiān)聽(tīng)器
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                //通過(guò)事件廣播中心ApplicationEventMulticaster葡盗,下發(fā)事件到具體的監(jiān)聽(tīng)器ApplicationListener
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

registerListeners 方法主要完成將監(jiān)聽(tīng)器注冊(cè)到事件廣播中心實(shí)例中螟左,在initApplicationEventMulticaster創(chuàng)建了事件廣播中心實(shí)例,但廣播中心還沒(méi)有持有任何監(jiān)聽(tīng)器觅够,這步主要完成監(jiān)聽(tīng)器的注冊(cè)胶背,以便事件下發(fā)時(shí),能找到對(duì)應(yīng)的監(jiān)聽(tīng)器喘先。

spring 通過(guò)如下方式獲取監(jiān)聽(tīng)器钳吟,并注冊(cè)的廣播中心:

  1. 獲取容器中靜態(tài)設(shè)置的監(jiān)聽(tīng)器注冊(cè)
  2. 通過(guò)beanFactory中查找監(jiān)聽(tīng)器注冊(cè)

registerListeners 還完成了(下發(fā)在事件機(jī)制初始化完成前的發(fā)布事件)功能,ApplicaitonContext將事件機(jī)制未初始化完成前發(fā)布的事件保存在earlyApplicationEvents集合中窘拯,當(dāng)前事件機(jī)制完成后統(tǒng)一下發(fā)到事件監(jiān)聽(tīng)器红且。實(shí)現(xiàn)就是在registerListeners方法中,代碼如下:

    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                //通過(guò)事件廣播中心ApplicationEventMulticaster涤姊,下發(fā)事件到具體的監(jiān)聽(tīng)器ApplicationListener
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }

ApplicaitonContext事件發(fā)布

//類 AbstractApplicationContext
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        //當(dāng)事件機(jī)制未初始化完成前暇番,將下發(fā)的事件保存在集合中,等待事件機(jī)制初始化完成后統(tǒng)一下發(fā)
        // Multicast right now if possible - or lazily once the multicaster is initialized
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        }
        else {
            // 事件機(jī)制初始化完成思喊,調(diào)用事件廣播中心下發(fā)事件
            getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
        }
        // 將事件透?jìng)鞯礁干舷挛沫h(huán)境
        // Publish event via parent context as well...
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
            }
            else {
                this.parent.publishEvent(event);
            }
        }
    }

ApplicaitonContext繼承事件發(fā)布者接口壁酬,具有了事件發(fā)布的功能,ApplicaitonContext事件發(fā)布完成如下操作:

  1. 事件機(jī)制未初始化完成恨课,將事件保存到set集合舆乔。
  2. 事件機(jī)制初始化完成,調(diào)用事件廣播器庄呈,發(fā)布事件
  3. 將事件透?jìng)鞯礁讣?jí)上下問(wèn)環(huán)境ApplicaitonContext

事件機(jī)制初始化總結(jié): ApplicaitonContext 的refresh方法調(diào)用完成后蜕煌,就完成了整個(gè)事件機(jī)制的初始化工作,并將上下文中未下發(fā)到監(jiān)聽(tīng)器的事件統(tǒng)一通過(guò)事件廣播中心下發(fā)到事件監(jiān)聽(tīng)器诬留。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末斜纪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子文兑,更是在濱河造成了極大的恐慌盒刚,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绿贞,死亡現(xiàn)場(chǎng)離奇詭異因块,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)籍铁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)涡上,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)趾断,“玉大人,你說(shuō)我怎么就攤上這事吩愧∮笞茫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵雁佳,是天一觀的道長(zhǎng)脐帝。 經(jīng)常有香客問(wèn)我,道長(zhǎng)糖权,這世上最難降的妖魔是什么堵腹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮星澳,結(jié)果婚禮上疚顷,老公的妹妹穿的比我還像新娘。我一直安慰自己募判,他們只是感情好荡含,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著届垫,像睡著了一般释液。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上装处,一...
    開(kāi)封第一講書(shū)人閱讀 49,850評(píng)論 1 290
  • 那天误债,我揣著相機(jī)與錄音,去河邊找鬼妄迁。 笑死寝蹈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的登淘。 我是一名探鬼主播箫老,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼黔州!你這毒婦竟也來(lái)了耍鬓?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤流妻,失蹤者是張志新(化名)和其女友劉穎牲蜀,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體绅这,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涣达,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片度苔。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡匆篓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出林螃,到底是詐尸還是另有隱情奕删,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布疗认,位于F島的核電站,受9級(jí)特大地震影響伏钠,放射性物質(zhì)發(fā)生泄漏横漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一熟掂、第九天 我趴在偏房一處隱蔽的房頂上張望缎浇。 院中可真熱鬧,春花似錦赴肚、人聲如沸素跺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)指厌。三九已至,卻和暖如春踊跟,著一層夾襖步出監(jiān)牢的瞬間踩验,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工商玫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留箕憾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓拳昌,卻偏偏與公主長(zhǎng)得像袭异,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子炬藤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,092評(píng)論 1 32
  • 官方文檔 初始化 Initialization是為準(zhǔn)備使用類御铃,結(jié)構(gòu)體或者枚舉實(shí)例的一個(gè)過(guò)程。這個(gè)過(guò)程涉及了在實(shí)例里...
    hrscy閱讀 1,133評(píng)論 0 1
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,773評(píng)論 6 342
  • 1刻像、你說(shuō)夢(mèng)到我了 夢(mèng)到你回來(lái)找我畅买,然后看到我后,兩個(gè)人一起抱著瞎哭细睡。我說(shuō)這特別特別有可能谷羞,我們兩個(gè)啊都是愛(ài)哭...
    么么姚閱讀 344評(píng)論 0 0
  • ps aux | grep nginx 查看指定進(jìn)程sudo kill -9 400 ...
    流動(dòng)碼文閱讀 245評(píng)論 0 0