javascript
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)); }從當前代碼中可以看出注冊加載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() 方法
parseCustomElement() 方法
主要解析自定義的標簽內容
比如:
本人簡書blog地址:http://www.jianshu.com/u/1f0067e24ff8????
點擊這里快速進入簡書
GIT地址:http://git.oschina.net/brucekankan/
點擊這里快速進入GIT
總結
以上是生活随笔為你收集整理的Spring 加载、解析applicationContext.xml 流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring bean 基于xml的4中
- 下一篇: gradle idea java ssm