Spring源碼之六-onRefresh()方法

原文地址:https://segmentfault.com/a/1190000041493352

今天帶大家解讀Spirng源碼之六的onRefresh()方法税朴,這是refresh()的其中的一個方法回季,看似是一個空方法,實則他是非常非常重要的正林,對于提高Spring的擴(kuò)展性泡一。

老規(guī)矩,先貼上Spring的核心方法refresh()方法的源碼觅廓,以便讀者可以絲滑入戲鼻忠。

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            //1、刷新前的準(zhǔn)備
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            //2杈绸、將會初始化 BeanFactory帖蔓、加載 Bean、注冊 Bean
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            //3瞳脓、設(shè)置 BeanFactory 的類加載器塑娇,添加幾個 BeanPostProcessor,手動注冊幾個特殊的 bean
            prepareBeanFactory(beanFactory);

            try {
                //4劫侧、模板方法
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                //執(zhí)行BeanFactory后置處理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // 5埋酬、Register bean processors that intercept bean creation.
                //注冊bean后置處理器
                registerBeanPostProcessors(beanFactory);

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

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                //6、模板方法--springboot實現(xiàn)了這個方法
                onRefresh();

                // Check for listener beans and register them.
                //7、注冊監(jiān)聽器
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                //8奇瘦、完成bean工廠的初始化**方法**********************************************
                finishBeanFactoryInitialization(beanFactory);

                //9棘催、 Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }
onRefresh()是模板方法,具體的子類可以在這里初始化一些特殊的 Bean(在初始化 singleton beans 之前)

這是onRefresh()的主要作用耳标,那么文章到這里就結(jié)束了醇坝,感謝閱讀!

開玩笑次坡,只說作用不舉例那和耍流氓沒有什么區(qū)別呼猪,接下來就以Spirng的典型實現(xiàn)Springboot來舉例。

該方法的執(zhí)行時機(jī)是Spring已經(jīng)加載好了一些特殊的bean(內(nèi)置的一些bean砸琅,實現(xiàn)了bean工廠后置處理器的類)之后宋距,在實例化單例bean之前。讓我們來看Springboot是怎么調(diào)用這個模板方法的症脂。

一路的點擊Springboot的核心入口run()方法谚赎,一路找到了我們今天的主角,Spring的refresh()方法中的onRefresh()方法诱篷。

點擊查看Springboot的onRresh()的實現(xiàn)方法壶唤。

有兩個包路徑含有boot的,一定就是Spirngboot的實現(xiàn)方法棕所。

image.png

這是Spirng的onRresh()的實現(xiàn)方法闸盔。

image.png

比對一下Spirng的onRresh()和SpirngbootRefersh的實現(xiàn)類對比,Springboot多了兩個實現(xiàn)類琳省,ReactiveWebServerApplicationContext類和ServletWebServerApplicationContext類迎吵。

我們分別查看這兩個實現(xiàn)的onRresh()方法都做了什么?

方法名都是createWebServer()方法针贬,以為這兩個方法都是一個方法击费,仔細(xì)一看發(fā)現(xiàn)并不是。

image.png

兩個createWebServer()方法做了什么呢桦他?我們debug進(jìn)去摟一眼荡灾。

ReactiveWebServerApplicationContext類的onRresh()方法并沒有執(zhí)行到,見名知意應(yīng)該是跟webServer管理相關(guān)的瞬铸,限于篇幅問題批幌,留個坑暫時放在吧。

image.png

ServletWebServerApplicationContext類的onRefresh()方法執(zhí)行到了嗓节,我們進(jìn)去一探究竟荧缘。

    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = getServletContext();
        //第一次進(jìn)來webServer servletContext都是null,會進(jìn)到if分支里面
        if (webServer == null && servletContext == null) {
            //這里就會來查找ServletWebServerFactory,也就是web容器的工廠,具體看下getWebServerFactory()方法拦宣,
            // 還是ServletWebServerApplicationContext這個類的方法
            //創(chuàng)建了 TomcatServletWebServerFactory 類
            ServletWebServerFactory factory = getWebServerFactory();
            //創(chuàng)建 Tomcat
            this.webServer = factory.getWebServer(getSelfInitializer());
        }
        else if (servletContext != null) {
            try {
                getSelfInitializer().onStartup(servletContext);
            }
            catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context", ex);
            }
        }
        initPropertySources();
    }

核心應(yīng)該是 factory.getWebServer(getSelfInitializer())截粗,這個方法是創(chuàng)建了一個容器信姓。都有哪些容器呢?

image.png

我們看一下他的實現(xiàn)類有Jetty绸罗、Mock意推、Tomcat*,Tomcat就不必提了珊蟀,Jetty略有耳聞和Tomcat并列的容易菊值。

那mock是什么呢,帶著求知的態(tài)度百度一下育灸,沒看懂腻窒,過!

image.png

我們還是重點看Tomcat磅崭。進(jìn)去看TomcatServletWebServerFactory的實現(xiàn)類儿子,new了一個Tomcat的對象,并做了一些Tomcat的設(shè)置砸喻,什么協(xié)議柔逼、端口......等等。

@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
   if (this.disableMBeanRegistry) {
      Registry.disableRegistry();
   }
   //創(chuàng)建 Tomcat
   Tomcat tomcat = new Tomcat();
   File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
   tomcat.setBaseDir(baseDir.getAbsolutePath());
   // 同步非阻塞io協(xié)議
   Connector connector = new Connector(this.protocol);
   connector.setThrowOnFailure(true);
   tomcat.getService().addConnector(connector);
   customizeConnector(connector);
   tomcat.setConnector(connector);
   tomcat.getHost().setAutoDeploy(false);
   configureEngine(tomcat.getEngine());
   for (Connector additionalConnector : this.additionalTomcatConnectors) {
      tomcat.getService().addConnector(additionalConnector);
   }
   prepareContext(tomcat.getHost(), initializers);
   //這里會創(chuàng)建 TomcatWebServer 實例, 并返回
   return getTomcatWebServer(tomcat);
}

好了割岛,到此就把spirng的模板方法onRefresh()在Springboot中是怎么用的說說清楚了卒落,順道把Tomcat是怎么內(nèi)嵌到Springboot中簡要的講解了一下。

貌似有點跑題了蜂桶,講onRefresh()方法呢,結(jié)果在springboot中饒了一大圈也切。不過扑媚,能讓讀者更好的理解Spirng和Springboot的關(guān)系,能認(rèn)真的讀讀也是大有裨益的雷恃。

也是真的感嘆Spirng作者們的功力之強疆股,Spirng的擴(kuò)展性有多少的強大。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末倒槐,一起剝皮案震驚了整個濱河市旬痹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌讨越,老刑警劉巖两残,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異把跨,居然都是意外死亡人弓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門着逐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來崔赌,“玉大人意蛀,你說我怎么就攤上這事〗“牛” “怎么了外遇?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵譬猫,是天一觀的道長。 經(jīng)常有香客問我,道長眼耀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任净蚤,我火速辦了婚禮骨坑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狭瞎。我一直安慰自己细移,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布熊锭。 她就那樣靜靜地躺著弧轧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碗殷。 梳的紋絲不亂的頭發(fā)上精绎,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音锌妻,去河邊找鬼代乃。 笑死,一個胖子當(dāng)著我的面吹牛仿粹,可吹牛的內(nèi)容都是我干的搁吓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼吭历,長吁一口氣:“原來是場噩夢啊……” “哼堕仔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起晌区,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤摩骨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后朗若,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恼五,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年哭懈,在試婚紗的時候發(fā)現(xiàn)自己被綠了唤冈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡银伟,死狀恐怖你虹,靈堂內(nèi)的尸體忽然破棺而出绘搞,到底是詐尸還是另有隱情,我是刑警寧澤傅物,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布夯辖,位于F島的核電站,受9級特大地震影響董饰,放射性物質(zhì)發(fā)生泄漏蒿褂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一卒暂、第九天 我趴在偏房一處隱蔽的房頂上張望啄栓。 院中可真熱鬧,春花似錦也祠、人聲如沸昙楚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽堪旧。三九已至,卻和暖如春奖亚,著一層夾襖步出監(jiān)牢的瞬間淳梦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工昔字, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留爆袍,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓作郭,卻偏偏與公主長得像陨囊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子所坯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

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