Spring源碼分析(一) XmlWebApplicationContext

spring是大家都會用的ioc框架碟狞,但是要真的了解spring還是需要好好研究一下才行啄枕,為此看了一些spring源碼,所以開始寫spring源碼分析的文章族沃,這個是第一篇频祝,先從ioc容器的啟動開始。
我們都知道,spring的ioc容器的最基本的接口就是BeanFactory,而ApplicationContext是包含了BeanFactory的所有信息脆淹,所以ioc容器在啟動的時候就是從AbstractApplicationContext的refresh方法開始的

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) { // 加鎖常空,避免 #refresh() 和 #close() 方法,自身或者對方并行執(zhí)行盖溺。
        // Prepare this context for refreshing.
        // 準備刷新的上下文
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        // 初始化 BeanFactory 漓糙,并進行 XML 文件讀取
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // 對 BeanFactory 進行各種功能填充。
        // TODO 包括對 @Autowired 和 @Qualifier 注解的屬性注入
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 子類覆蓋該方法烘嘱,做 BeanFactory 的額外的處理
            postProcessBeanFactory(beanFactory);
            // Invoke factory processors registered as beans in the context.
            // 激活各種 BeanFactory 處理器昆禽,例如 BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 注冊攔截 Bean 創(chuàng)建的 BeanPostProcessor。這里只是注冊蝇庭,真正的調用在 #getBean(...) 的時醉鳖,即 Bean 創(chuàng)建的時候。
            // 注意:
            //      1. BeanFactoryPostProcessor 作用于 BeanDefinition
            //      2. BeanPostProcessor 作用于 Bean
            registerBeanPostProcessors(beanFactory);

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

            // Initialize event multicaster for this context.
            // 初始化 Application Event Multicaster
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 留給子類哮内,來初始化其他特殊的 Bean 對象們
            onRefresh();

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

            // Instantiate all remaining (non-lazy-init) singletons.
            // 初始化非延遲加載的單例
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 完成 refresh 邏輯
            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方法,我們來看AbstractRefreshableWebApplicationContext這個類,在這個類中覆寫了onRefresh方法

protected void onRefresh() {
    this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}

這是什么東西北发?別急纹因,我們來看看themeSource是什么。

public static ThemeSource initThemeSource(ApplicationContext context) {
    if (context.containsLocalBean(THEME_SOURCE_BEAN_NAME)) {
        ThemeSource themeSource = context.getBean(THEME_SOURCE_BEAN_NAME, ThemeSource.class);
        // Make ThemeSource aware of parent ThemeSource.
        if (context.getParent() instanceof ThemeSource && themeSource instanceof HierarchicalThemeSource) {
            HierarchicalThemeSource hts = (HierarchicalThemeSource) themeSource;
            if (hts.getParentThemeSource() == null) {
                // Only set parent context as parent ThemeSource if no parent ThemeSource
                // registered already.
                hts.setParentThemeSource((ThemeSource) context.getParent());
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Using ThemeSource [" + themeSource + "]");
        }
        return themeSource;
    }
    else {
        // Use default ThemeSource to be able to accept getTheme calls, either
        // delegating to parent context's default or to local ResourceBundleThemeSource.
        HierarchicalThemeSource themeSource = null;
        if (context.getParent() instanceof ThemeSource) {
            themeSource = new DelegatingThemeSource();
            themeSource.setParentThemeSource((ThemeSource) context.getParent());
        }
        else {
            themeSource = new ResourceBundleThemeSource();
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate ThemeSource with name '" + THEME_SOURCE_BEAN_NAME +
                    "': using default [" + themeSource + "]");
        }
        return themeSource;
    }
}

還是不太明白鲫竞?那我們來看看AbstractRefreshableWebApplicationContext的結構

public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
    implements ConfigurableWebApplicationContext, ThemeSource

原來ThemeSource是一個接口,而AbstractRefreshableWebApplicationContext則實現(xiàn)了這個接口,在onRefresh把自己傳進去了辐怕,好吧逼蒙,這塊就先看到這里从绘。
我們直接到XmlWebApplicationContext這個類里,我們發(fā)現(xiàn)AbstractRefreshableApplicationContext類有一個方法loadBeanDefinitions,而XmlWebApplicationContext覆寫了這個方法,我們來看看XmlWebApplicationContext是怎么實現(xiàn)的

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    beanDefinitionReader.setEnvironment(getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}

這里我們要介紹ioc容器里的一個接口BeanDefinitionReader,而XmlBeanDefinitionReader是BeanDefinitionReader的一個實現(xiàn)類,負責對xml的配置文件進行讀取,并放到ioc容器中。當讀取完配置文件后,通過loadBeanDefinitions方法將bean注冊到ioc容器中僵井。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        for (String configLocation : configLocations) {
            reader.loadBeanDefinitions(configLocation);
        }
    }
}

至此陕截,ioc容器就啟動完成。
XmlWebApplicationContext的分析就到這里了批什。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末农曲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子驻债,更是在濱河造成了極大的恐慌乳规,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件合呐,死亡現(xiàn)場離奇詭異暮的,居然都是意外死亡,警方通過查閱死者的電腦和手機淌实,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門冻辩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拆祈,你說我怎么就攤上這事恨闪。” “怎么了放坏?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵咙咽,是天一觀的道長。 經(jīng)常有香客問我淤年,道長犁珠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任互亮,我火速辦了婚禮犁享,結果婚禮上,老公的妹妹穿的比我還像新娘豹休。我一直安慰自己炊昆,他們只是感情好,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布威根。 她就那樣靜靜地躺著凤巨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪洛搀。 梳的紋絲不亂的頭發(fā)上敢茁,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天,我揣著相機與錄音留美,去河邊找鬼彰檬。 笑死伸刃,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的逢倍。 我是一名探鬼主播捧颅,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼较雕!你這毒婦竟也來了碉哑?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤亮蒋,失蹤者是張志新(化名)和其女友劉穎扣典,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慎玖,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡激捏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡体箕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出图柏,到底是詐尸還是另有隱情,我是刑警寧澤任连,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布蚤吹,位于F島的核電站,受9級特大地震影響随抠,放射性物質發(fā)生泄漏裁着。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一拱她、第九天 我趴在偏房一處隱蔽的房頂上張望二驰。 院中可真熱鬧,春花似錦秉沼、人聲如沸桶雀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矗积。三九已至,卻和暖如春敞咧,著一層夾襖步出監(jiān)牢的瞬間棘捣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工休建, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留乍恐,地道東北人评疗。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像禁熏,于是被迫代替她去往敵國和親壤巷。 傳聞我的和親對象是個殘疾皇子邑彪,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355

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