XmlBeanDefinitionReader-----Spring源码解析 配置文件装载与解析
来源:互联网 发布:php mysql集成环境 编辑:程序博客网 时间:2024/05/22 07:40
原文出自:http://leayer.iteye.com/blog/806016
以下内容有部分摘自网络
步骤A. 读取 Resource 文件形成 Document 模型
类图: XmlBeanFactory -> XmlBeanDefinitionReader
Spring 使用 XmlBeanDefinitionReader 来读取并解析 xml 文件,XmlBeanDefinitionReader 是 BeanDefinitionReader 接口的实现。
BeanDefinitionReader 定义了 Spring 读取 Bean 定义的一个接口,这个接口中有一些 loadBeanDefinitions 方法, 用于读取 Bean 配置。
BeanDefinitionReader 接口有两个具体的实现,其中之一就是从 Xml 文件中读取配置的 XmlBeanDefinitionReader,另一个则是从 Java Properties 文件中读取配置的PropertiesBeanDefinitionReader。
(注:开发人员也可以提供自己的 BeanDefinitionReader 实现,根据自己的需要来读取 spring bean 定义的配置。)
步骤B. 解析 Document 得到 Bean 配置
类图: XmlBeanDefinitionReader-> BeanDefinitionDocumentReader
BeanDefinitionDocumentReader 接口中只定义了一个方法 registerBeanDefinitions. 有一个默认实现 DefaultBeanDefinitionDocumentReader.
DefaultBeanDefinitionDocumentReader 主要完成两件事情,解析 <bean> 元素,为扩展 spring 的元素寻找合适的解析器,并把相应的元素交给解析器解析。
过程:
在 XmlBeanFactory 中创建了 XmlBeanDefinitionReader 的实例,并在 XmlBeanFactory 的构造方法中调用了 XmlBeanDefinitionReader 的 loadBeanDefinitions 方法,由 loadBeanDefinitions 方法负责加载 bean 配置并把 bean 配置注册到 XmlBeanFactory 中。
在 XmlBeanDefinitionReader 的 loadBeanDefinitions 方法中, 调用 DefaultDocumentLoader 的 loadDocument 读取配置文件为 Document, 然后调用 BeanDefinitionDocumentReader 的 registerBeanDefinitions 方法 来解析 Bean.
源码解析:
在XmlBeanFactory初始化时, 需要指定Resource对象.
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); reader = new XmlBeanDefinitionReader(this); reader.loadBeanDefinitions(resource); }
1. 先来分析下XmlBeanDefinitionReader这个类.
接着
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader
再继续
public interface BeanDefinitionReader
在BeanDefinitionReader中定义有许多loadBeanDefinitions方法
public abstract int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException; public abstract int loadBeanDefinitions(Resource aresource[]) throws BeanDefinitionStoreException; public abstract int loadBeanDefinitions(String s) throws BeanDefinitionStoreException; public abstract int loadBeanDefinitions(String as[]) throws BeanDefinitionStoreException;
来回头看XmlBeanDefinitionReader对loadBeanDefinitions方法的实现
在loadBeanDefinitions方法中调用了doLoadBeanDefinitions方法, 跟踪doLoadBeanDefinitions方法
通过一个叫documentLoader的东西的loadDocument方法来加载配置文件形成DOM, 来看看documentLoader
private DocumentLoader documentLoader ... documentLoader = new DefaultDocumentLoader();
跟踪到DefaultDocumentLoader
public class DefaultDocumentLoader implements DocumentLoader ... public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if(logger.isDebugEnabled()) logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); } ...
在这一步, 已完成了从配置文件读取到Domcument. 接着要开始解析Dom了
再继续, 解析成Dom后接着调用了registerBeanDefinitions方法
来看看registerBeanDefinitions的实现
... BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; ...
在这里, 有一个BeanDefinitionDocumentReader接口, 实际上Spring对它有一个默认的实现类叫DefaultBeanDefinitionDocumentReader, 来看看它的家族
BeanDefinitionDocumentReader只有一个registerBeanDefinitions方法
public abstract void registerBeanDefinitions(Document document, XmlReaderContext xmlreadercontext) throws BeanDefinitionStoreException;
该方法需要两个参数, 一个是Document模型,这个应该是我们读取配置文件获取到的, 另一个是XmlReaderContext对象, 我们在上面方法中看到是通过createReaderContext(resource)得到的, 那就看看具体如何得到
protected XmlReaderContext createReaderContext(Resource resource) { if(namespaceHandlerResolver == null) namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); return new XmlReaderContext(resource, problemReporter, eventListener, sourceExtractor, this, namespaceHandlerResolver); }
能过构造函数new出来的, 且有一个重要参数resource
再继续来看DefaultBeanDefinitionDocumentReader对BeanDefinitionDocumentReader的registerBeanDefinitions方法实现
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { ... BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); ... parseBeanDefinitions(root, delegate); ... }
嘿嘿, 开始解析Dom了哦, 其中主要是parseBeanDefinitions方法, 来看看具体是如何解析的
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if(delegate.isDefaultNamespace(root.getNamespaceURI())) { NodeList nl = root.getChildNodes(); for(int i = 0; i < nl.getLength(); i++) { org.w3c.dom.Node node = nl.item(i); if(node instanceof Element) { Element ele = (Element)node; String namespaceUri = ele.getNamespaceURI(); if(delegate.isDefaultNamespace(namespaceUri)) parseDefaultElement(ele, delegate); else delegate.parseCustomElement(ele); } } } else { delegate.parseCustomElement(root); } }
看到了吧, 循环解析Domcument节点
parseDefaultElement方法和delegate的parseCustomElement方法
先来看parseDefaultElement方法
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if(DomUtils.nodeNameEquals(ele, "import")) importBeanDefinitionResource(ele); else if(DomUtils.nodeNameEquals(ele, "alias")) processAliasRegistration(ele); else if(DomUtils.nodeNameEquals(ele, "bean")) processBeanDefinition(ele, delegate); }
看到这就很清楚了, 就是根据节点的名称作不同解析, 如我们Spring配置文件中常有以下几种配置
<import resource="classpath:xxx" /> <bean id="xxx" class="xxx.xxx.xxx" /> <alias name="xxxx" alias="yyyyy"/>
对<import>节点, 调用importBeanDefinitionResource方法解析, 此方法中, 又回到第一步读取配置文件并解析. 如此递归循环.
... Resource relativeResource = getReaderContext().getResource().createRelative(location); int importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); ...
对<alias>节点, 调用processAliasRegistration进行别名解析
我们主要看对<bean>节点调用processBeanDefinition进行解析
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if(bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch(BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
public class BeanDefinitionParserDelegate { private final Set usedNames = new HashSet(); ... public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { ... 解析id, name等属性, 并验证name是否唯一, 并将name保存在usedNames中 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); ... return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } ... }
OK, 重头戏开始, 最经典的部分出现了, 请看parseBeanDefinitionElement方法
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) { ... 代码太长, 请参考具体代码 AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(parent, className, readerContext.getBeanClassLoader()); ... return abstractbeandefinition; ... }
这一步将节点解析成BeanDefinitionHolder对象, 再看看如何注册, 回到DefaultBeanDefinitionDocumentReader的processBeanDefinition方法
看到对解析到的bdHolder对象又做了decorateBeanDefinitionIfRequired操作, 来看看实现
... 暂留空
接着调用了BeanDefinitionReaderUtils的registerBeanDefinition方法注册bdHolder, 来看看如何实现的
public class BeanDefinitionReaderUtils { public static void registerBeanDefinition(BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory) throws BeanDefinitionStoreException { String beanName = bdHolder.getBeanName(); beanFactory.registerBeanDefinition(beanName, bdHolder.getBeanDefinition()); String aliases[] = bdHolder.getAliases(); if(aliases != null) { for(int i = 0; i < aliases.length; i++) beanFactory.registerAlias(beanName, aliases[i]); } } }
看吧, 又调用了BeanDefinitionRegistry的registerBeanDefinition方法, 跟踪之 (这个要看DefaultListableBeanFactory的实现)
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry { private final Map beanDefinitionMap; private final List beanDefinitionNames; ... public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { ... Object oldBeanDefinition = beanDefinitionMap.get(beanName); ... beanDefinitionMap.put(beanName, beanDefinition); ... } }
这里, 看到了一个最最重要的对象就是beanDefinitionMap, 这个map存放了所有的bean对象, 和我们通常讲的容器概念最为接近, getBean时实际是也是从这里辚取对象, 相同的还有一个beanDefinitionNames, 但这个只保存bean的名称
完成上面之后, 还有一步操作beanFactory.registerAlias(beanName, aliases[i]);
这个实现实际是上AbstractBeanFactory抽象类所定义的
是不是特兴奋, 已经揭开它神秘的面纱了
定义 -> 定位 -> 装载 -> 注册 这几步已经完成了, 以后继续看Spring是如何创建bean及实例化的
0 0
- XmlBeanDefinitionReader-----Spring源码解析 配置文件装载与解析
- Spring源码解析配置文件装载与解析
- Spring源码解析 配置文件装载与解析
- 解析Spring源码(4)--XmlBeanDefinitionReader
- 解析Spring源码(9)--XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
- 解析Spring源码(3)---XmlBeanDefinitionReader(1)
- spring 读取配置文件源码解析
- Spring源码浅析 -- XML配置文件的载入与解析
- Spring源码浅析 -- XML配置文件的载入与解析
- spring 源码解读与设计详解:5 XmlBeanDefinitionReader与Resource
- spring源码之XmlBeanDefinitionReader与bean的注册
- xmlBeanDefinitionReader解析xml的过程
- Spring源码解析--Spring配置文件解析BeanDefinitionParserDelegate(四)
- Spring源码解析--Spring配置文件解析NamespaceHandler(五)
- Spring源码分析-配置文件的解析(二)
- spring源码解读-加载解析配置文件
- Spring源码解析和配置文件加载
- Spring源码学习--Spring配置文件解析BeanDefinitionDocumentReader(三)
- ASE 进程为send sleep如何解决
- 微博上市让新浪又站上“浪尖”
- 执行Action前显示确认窗口
- LIBSVM 在matlab 2013添加 VS2013 c++编译器
- 超级下饭菜--金针菇日本豆腐
- XmlBeanDefinitionReader-----Spring源码解析 配置文件装载与解析
- Android 第三方应用接入微信平台研究情况分享(一) 详细出处参考:http://www.jb51.net/article/33048.htm
- iphone之家网站 iphonezhijia.com 关于iphone资讯 iphone游戏 iphone应用 iphone游戏攻略的网站
- ABAP 技术总结
- Partition expansion failed Please run a file system check
- 二维码类型
- Android之selecter
- android的Fragment解析(一行代码引发的思考)
- JAVA-单例模式