概要

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 />

本人简书blog地址:http://www.jianshu.com/u/1f0067e24ff8    
点击这里快速进入简书

GIT地址:http://git.oschina.net/brucekankan/
点击这里快速进入GIT

Spring 加载、解析applicationContext.xml 流程相关推荐

  1. Spring源码解析-applicationContext.xml加载和bean的注册

    applicationContext文件加载和bean注册流程 ​ Spring对于从事Java开发的boy来说,再熟悉不过了,对于我们这个牛逼的框架的介绍就不在这里复述了,Spring这个大杂烩,怎 ...

  2. Tomcat原理系列之四:Tomat如何启动spring(加载web.xml)

    Tomcat原理系列之四:Tomat如何启动spring 熟悉的web.xml ContextLoaderListener Tomcat的初始化StandardContext.startInterna ...

  3. 如何获得spring配置文件头部配置(applicationContext.xml)

    目录 一.文章前言 二.applicationContext.xml查找 一.文章前言 Spring需要加载配置文件applicationContext.xml,那么自带的jar包又没有,该如何查找: ...

  4. 有没有code能改xml内容_Spring源码解析-applicationContext.xml加载和bean的注册

    applicationContext文件加载和bean注册流程 ​ Spring对于从事Java开发的boy来说,再熟悉不过了,对于我们这个牛逼的框架的介绍就不在这里复述了,Spring这个大杂烩,怎 ...

  5. spring加载ApplicationContext.xml的四种方式

    spring加载ApplicationContext.xml的四种方式 spring 中加载xml配置文件的方式,好像有4种, xml是最常见的spring 应用系统配置源.Spring中的几种容器都 ...

  6. java spring 加载bean,Spring多种加载Bean方式解析

    1 定义bean的方式 常见的定义Bean的方式有: 通过xml的方式,例如: ? 通过注解的方式,在Class上使用@Component等注解,例如 ? 通过在@Configuration类下的@B ...

  7. Spring ContextLoaderListener与DispatcherServlet所加载的applicationContext的区别

    spring通过在web.xml 中配置ContextLoaderListener 来加载context配置文件,在DispatcherServlet中也可以来加载spring context配置文件 ...

  8. Spring加载流程源码

    一.从AbstractApplicationContext的体系说起 第一,从类结构设计上看, 围绕着是否需要Refresh容器衍生出两个抽象类: GenericApplicationContext: ...

  9. java类spring加载_spring的加载机制?

    1,今天面试官问我spring的加载机制有哪些---这么"抽象"的问题作为一个十多年经验的自己写过MVC,IOC,ORM, 等各种中间件小框架的开发人员也回答不出来~ 确切的说是无 ...

最新文章

  1. 周志华出任京东人工智能研究院学术委员会委员
  2. TACACS 协议简介与开发总结
  3. 自然语言处理之词向量技术(二)
  4. STM8学习笔记---定时器 TIM4功能实现
  5. python保存数据_python各数据存储方法
  6. android 生成签名和SHA1签名信息
  7. 光线传感器,方向传感器Android
  8. 画图软件Microsoft visio下载安装及使用
  9. 利用Signalr实现手机端App扫码登录web页面
  10. 窗体泄露 WindowManager: android.view.WindowLeaked: Activity com.XXX.XXX.activity.XXXActivity has leaked
  11. 洛谷P4518 [JSOI2018]绝地反击(计算几何+二分图+退流)
  12. 靠卖艺还债:罗永浩的冬天来了!
  13. 举个栗子!Tableau技巧(7):如何做帕累托图
  14. 非常适合新手的一个Python爬虫项目: 打造一个英文词汇量测试脚本!
  15. 基于扩张状态观测器eso扰动补偿和权重因子调节的电流预测控制,相比传统方法,增加了参数鲁棒性
  16. kafka身份认证 maxwell_Kafka 使用SASL / SCRAM进行身份验证
  17. PTA-python练习题-2(简单的计算及输入输出①)
  18. 空气质量指数c语言,基于STM32的小范围空气质量的监测与预报
  19. fetchMetadata: sill resolveWithNewModule raw-loader@0.5.1 checking installable status
  20. 破解md5的python代码,持续更新

热门文章

  1. 五十六、 白话讲解商业智能 BI、数据仓库 DW、数据挖掘 DM
  2. 二十六、深入Python中的time和datetime模块
  3. 多样性文本生成任务的研究进展
  4. 从动力学角度看优化算法:为什么SimSiam不退化?
  5. 直播预告 | 旷视科技李彦玮:动态网络及其在场景分割中的应用
  6. 从 Word2Vec 到 BERT
  7. Russell大师课+大厂专家倾授+5小时黑客松,上海临港人工智能开发者大会倒计时5天...
  8. 线下沙龙 | 小身材大能量!用英伟达智能小车Jetbot玩转深度学习
  9. 【华为云踩坑】开启了入方向规则的 tcp/80 端口,仍然无法访问
  10. wpf 在另一个窗体上显示_另一个唐伯虎:大街上裸身奔跑、锒铛入狱多次自裁未遂...