1. 程式人生 > >Spring 載入、解析applicationContext.xml 流程

Spring 載入、解析applicationContext.xml 流程

概要

Spring 框架使用了BeanFactory 進行載入 xml 和生成 bean 例項。下面我們分析下Spring載入xml檔案的過程。
spring 版本是最新的 4.3.9 release 版本

示例

XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource("bean.xml"));
User user = User.class.cast(xbf.getBean("user"));
System.out.println(user);

我們通過XmlBeanFactory分析下xml的載入過程。通常我們開發的時候一般都是使用ClassPathXmlApplicationContext進行載入配置檔案的。原理都一樣,只不過ClassPathXmlApplicationContext寬展了好多功能。但載入xml的原理都一樣。

ClassPathResource 封裝了xml檔案資訊,可以呼叫getInputStream() 方法獲取檔案。

原始碼解析

XmlBeanFactory.java


從程式碼中發現XmlBeanFactory委託給XmlBeanDefintionReader進行處理

XmlBeanDefintionReader.java


1. 使用EncodeResource封裝資原始檔。如果指定編碼則使用指定編碼進行讀取資原始檔。
2. 判斷該資源是否已經載入過
3. 構造InputStream例項,然後呼叫 doLoadBeanDefinitions() 方法

InputSource 類結構
public class InputSource {
    private String publicId;
    private String systemId;
    private InputStream byteStream;
    private String encoding;
    private Reader characterStream;
    ....
}

使用SAX解析、驗證xml的時候需要使用到 publicId和systemId

doLoadBeanDefinitions() 方法


1. 使用SAX解析xml獲取Document物件
2. 根據返回的Document 註冊 Bean 資訊

doLoadDocument()

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
    return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
            getValidationModeForResource(resource), isNamespaceAware());
}

getValidationModeForResource(resource)


判斷xml的文件驗證機制是DTD還是XSD
1.如果指定驗證模式則使用指定的。
2.如果沒有指定則呼叫 detectValidationMode 自動檢查
讀取xml檔案中的是否保護“DOCTYPE”,如果包含則是DTD,否則則是XSD

getEntityResolver() 方法

EntityResovle作用:SAX解析xml的時候首先讀取xml文件上的宣告,根據宣告找相應的DTD定義。預設尋找規則:首先通過網路下載相應的DTD,並認證。網路下載是一個不確定的過程(網速問題、網路中斷等),就會出現DTD找不到的情況。而EntityResovle提供了一個尋找DTD的自定義方法,一般我們回吧DTD放到專案中某資料夾下,直接讀取本地的DTD交給SAX解析即可。避免了網路交換過程。

loadDocument() 方法


通過SAX解析xml。構造DocumentBuilderFactory解析xml。

registerBeanDefinitions() 方法

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
    }

protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
    return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
  1. 使用DefaultBeanDefinitionDocumentReader.class 構造BeanDefinitionDocumentReader 。
  2. 記錄已經載入的Bean的個數
  3. 載入及註冊Bean
  4. 返回這次載入的Bean的個數

從當前程式碼中可以看出註冊載入Bean委託給 BeanDefinitionDocumentReader .registerBeanDefinitions() 方法處理

registerBeanDefinitions() 方法

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    Element root = doc.getDocumentElement();
    doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);
    if (this.delegate.isDefaultNamespace(root)) {
        //判斷xml的beans標籤屬性中是否有profile屬性,並驗證跟web.xml中配置的資訊是否匹配
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                return;
            }
        }
    }
    preProcessXml(root);
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);
    this.delegate = parent;
}

profile 用法

<!-- spring的applicationContext.xml中配置 -->
<beans profile="development">
    ......
</beans>
<beans profile="produce">
    ......
</beans>

<!-- web專案的web.xml中配置 -->
<context-param>
    <param-name>spring.profiles.default</param-name>
    <param-value>production</param-value>
</context-param>

可以使用profile來進行切換線上配置和開發環境配置,方便開發使用

parseBeanDefinitions() 方法

判斷是自定義便籤還是系統預設標籤。
1.系統預設的標籤呼叫parseDefaultElement方法解析
2.使用者自定義標籤使用parseCustomElement方法解析

parseDefaultElement() 方法

  1. 解析 import 標籤
  2. 解析 alias 標籤
  3. 解析 bean 標籤
  4. 解析 beans 標籤

parseCustomElement() 方法

主要解析自定義的標籤內容
比如:

<!-- 使用者自定義標籤 -->
<bean id="xxx" class="test.XXX">
    <mybean:user username="zhangsan"/>
</bean>

<!-- 系統預設實現的自定義標籤 -->
<tx:annotation-driven />

相關推薦

Spring 載入解析applicationContext.xml 流程

概要 Spring 框架使用了BeanFactory 進行載入 xml 和生成 bean 例項。下面我們分析下Spring載入xml檔案的過程。 spring 版本是最新的 4.3.9 release 版本 示例 XmlBeanFactory x

Spring源碼解析-applicationContext.xml加載和bean的註冊

equal 完整 war 關系 ror 程序包 err do it web applicationContext文件加載和bean註冊流程? Spring對於從事Java開發的boy來說,再熟悉不過了,對於我們這個牛逼的框架的介紹就不在這裏復述了,Spring這個大雜燴,怎

Spring原始碼解析-applicationContext.xml載入和bean的註冊

Spring原始碼解析-applicationContext.xml載入和bean的註冊 萬事開頭難,就要從頭開始 Spring初始化 Spring是如何找到applicationContext.xml檔案 將xml檔

解釋為什麼Spring 預設會載入/WEB-INF/applicationContext.xml

/** * Instantiate the root WebApplicationContext for this loader, either the * default context class or a custom context class if speci

spring配置文件applicationContext.xml的路徑設置

framework pan 痛苦 erl -c 發現 load contex ade 先看web.xml 配置 1 <!-- 加載Spring容器配置 --> 2 <listener> 3 <listener-c

spring配置文件ApplicationContext.xml裏面class等沒有提示功能

myeclipse nbsp 分享 spring editors uri 應該 details views 實現效果: 解決方法: windows–>preference—>myeclipse—>files and editors–>xml—

spring bean的配置----applicationContext.xml

spring 配置檔案的根元素是<beans> ,<beans>中包含了多個<bean>子元素,每個<bean>元素定義一個Bean,並描述Bean如何被裝配到spring容器中。 bean元素常用屬性及其子元素如下

瀏覽器載入解析渲染的過程

最近在學習效能優化,學習了雅虎軍規 ,可是覺著有點雲裡霧裡的,因為裡面有些東西雖然自己也一直在使用,但是感覺不太明白所以然,比如減少DNS查詢,css和js檔案的順序。所以就花了時間去了解瀏覽器的工作,有一篇經典的文章《how browsers work》 ,講

web頁面載入解析渲染過程

對web專案進行優化首先得知道瀏覽器是怎麼工作的這裡推薦中文版; 一、瀏覽器 瀏覽器的主要功能是將使用者選擇的web資源呈現出來,它需要從伺服器請求資源,並將其顯示在瀏覽器視窗中,資源的格式通常是HTML,也包括PDF、image及其他格式。使用者用URI(Unifo

讀取Spring的配置檔案applicationContext.xml幾種方法

1).利用ClassPathXmlApplicationContext,這種方式配置檔案應該放在類路徑下,否則Spring將找不到該檔案。 Java程式碼: ApplicationContext ctx=new ClassPathXmlApplicationContext("

通過監聽器 獲取Spring載入後的applicationContext

最近遇到的是這樣一個問題:需要在Spring完成載入之後,獲取到Spring管理的 ApplicationContext。上網查了幾個方法,大家都說實現介面ApplicationContextAware實現該介面的setApplicationContext(Applicati

詳解Spring 啟動時解析WEB.xml過程

三:再次,contextLoaderListener監聽器初始化完畢後,開始初始化web.xml中配置的Servlet,這個servlet可以配置多個,以最常見的DispatcherServlet為例,這個servlet實際上是一個標準的前端控制器,用以轉發、匹配、處理每個servlet請求。Dispatch

Spring+Hibernate配置檔案-applicationContext.xml設定

搭建完整個工程之後,我們開啟applicationContext.xml檔案,在這個配置檔案中主要涉及的有Spring的相關配置以及Hibernate的相關配置。applicationContext.xml檔案的原始檔如下面所示: <?xml version="1.0

springapplicationContext.xml載入過程

    web容器在啟動時,會執行事先配置的監聽器ContextLoaderListener裡的contextInitialized方法,該方法再去呼叫了initWebApplicationContext方法。 該方法載入了ContextLoader類,在ContextLo

Spring Framework框架解析(1)- 從圖書館示例來看xml檔案的載入過程

引言 這個系列是我閱讀Spring原始碼後的一個總結,會從Spring Framework框架的整體結構進行分析,不會先入為主的講解IOC或者AOP的原理,如果讀者有使用Spring的經驗再好不過。鑑於每個人對原始碼閱讀角度的不同,如果文中存在理解有誤的地方希望讀者能夠及時提出,共同進步。文章所分析的原始碼

Spring載入bean定義流程原始碼解析

在本文中,先對Spring載入和建立bean例項的流程跟著原始碼走一遍,在後續的文章中再對所涉及的類的其他方法具體介紹。 //這一步是載入指定的配置檔案 Resource resource = new ClassPathResource("bean.xm

spring配置檔案頭部配置解析applicationContext.xml

分享一個好的學習網站:http://how2j.cn?p=4509      相信大家對spring的配置檔案應該都看的很多了,那麼大家對配置檔案頭部的那一坨坨的東西到底是什麼瞭解嗎?下面我就把自己的一些見解和大家分享一下: 首先拿一段大家熟悉的頭部配置檔案來看

J2EE for Spring在Idea裡無法載入applicationContext.xml問題解決(final)

昨天寫了一篇文章,解決idea中的無法載入application.xml的問題,無疑它能夠解決這個問題,但是後續會帶來諸多不便,假如我們刪除了web-inf中的xml,那必然會報錯。我們仍然使用當年eclipse裡的方法,這似乎有點跟不上節奏,在idea中的we

J2EE for Spring在Idea裡無法載入applicationContext.xml問題解決

本文並不能很好解決問題,請移步下文獲得最終的解決方案:最終解決方案 今天博主在學習spring,在此過程中可謂是問題一個接一個,最令人頭疼的還是載入xml檔案的問題,但是找了好多關於idea構建spring的博文均發現無用,問題依然得不到解決。終於,經過對Ec

Spring原始碼淺析 -- XML配置檔案的載入解析

最近在看Spring原始碼,對配置檔案資訊的載入是使用Spring的第一步 ,而這第一步就是一個非常複雜的過程....  Spring通過定義BeanDefination來管理Ioc中的各種物件以及它們之間的依賴關係,所以載入的過程其實就是將XML檔案讀取並解析成B