文件DefaultBeanDefinitionDocumentReader.java
首先解析入口是doRegisterBeanDefinitions这个函数。
1.首先创建一个ParseDelegate的类,第一次创建this.delegate没有被赋值为NULL.相当于
this.delegate = createDelegate(getReaderContext(), root, NULL);
  delegate就是 parse的实例对象,后续使用它的内部接口来解析XML,输入bean
2.delegate.initDefaults(root, null );
initDefaults这个函数是初如化一些默认的bean属性,这些属性会从XML读取,如果没有就用默认的。代码截图如下
理解这里的参数很重要,因为大部分xml bean的配置里面可能没有设置相关属性.用的都是默认值,如果不知道默认值是多少就比较麻烦

3.初如化完成后就开始1图的parseBeanDefinitions函数调用开始解析xml了,parseBeanDefinitions内容截图如下
一个xml里面可能有多个Node,parseBeanDefinitions里搞了个循环来处理所有的node.然后就是解析元素了。这里会针对几个元素进行处理
if “import” == NodeName -> importBeanDefinitionResource
if “alias” == NodeName -> processAliasRegistration
if “bean” == NodeName -> processBeanDefinition
if “beans” == NodeName -> doRegisterBeanDefinitions
这里只对processBeanDefinition进行跟踪,看bean的解析过程。
代码如下:

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {String id = ele.getAttribute(ID_ATTRIBUTE);String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

//上面两行代码就是读取bean id和bean name ID_ATTRIBUTE=“id” NAME_ATTRIBUTE = "name"
List aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
//上面几行代码大意是:首先看name属性是不是为空,如果不是则解析它。根据代码可知name可以有多个标识符,标识符与标识符之间可以用, ;和空格来分隔。其中MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; "; 然后存放到List数组aliases里面

 String beanName = id;if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {beanName = aliases.remove(0);if (logger.isTraceEnabled()) {logger.trace("No XML 'id' specified - using '" + beanName +"' as bean name and " + aliases + " as aliases");}}**

//上面几行代码大体意思是,将读取的id赋值给beanName。如果beanName为空也就是id为空,则读取name属性的第一个标识符同时将其移出LIS**

 if (containingBean == null) {checkNameUniqueness(beanName, aliases, ele);}

//上面一段代码主要作了一些检查,并将数据COPY到全局变量中去

 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);if (beanDefinition != null) {if (!StringUtils.hasText(beanName)) {try {if (containingBean != null) {beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);}else {beanName = this.readerContext.generateBeanName(beanDefinition);// Register an alias for the plain bean class name, if still possible,// if the generator returned the class name plus a suffix.// This is expected for Spring 1.2/2.0 backwards compatibility.String beanClassName = beanDefinition.getBeanClassName();if (beanClassName != null &&beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {aliases.add(beanClassName);}}if (logger.isTraceEnabled()) {logger.trace("Neither XML 'id' nor 'name' specified - " +"using generated bean name [" + beanName + "]");}}catch (Exception ex) {error(ex.getMessage(), ele);return null;}}String[] aliasesArray = StringUtils.toStringArray(aliases);return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);}return null;
}
parseBeanDefinitionElement多态函数调用,截图如下。

1.首先会获取class值CLASS_ATTRIBUTE = “class”  
2 . 再次看它是否有parent属性,有就读取PARENT_ATTRIBUTE = “parent”
3. 根据类名和parent创建一个AbstractBeanDefinition对象。如下图,创建过程比较简单

从上两幅图可以看出,这个相当简单,就是new了一个GenericBeanDefinition对象,然后把传递过的数据,直接赋值就好了。
4。解析 bean 的各种初始化属性值parseBeanDefinitionAttributes函数截图如下
从上图可以看出这里在尝试从xml配置文件中读取各种bean 对象初始化需要的各种属性。如果没有找到,则使用默认的属性或者不作操作
代码简单明了,不作过多解释。

5。 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
这段代码也很简单,主要是获取描述文字,然后填充成员变量,这里给出一段bean配置的截图就明白了
一般在一个bean里面就只有一个 description属性.而对属性位置没有要求,只要在bean里面就可以。

6。 parseMetaElements(ele, bd);
解析meta 属性META_ELEMENT = “meta”。如果有meta 则读取meta里面的key和value属性。然后用这两个数据生成一个BeanMetadataAttribute对象。然后添加到bd的attributes成员变量里面中。注意AbstractBeanDefinition继承BeanMetadataAttributeAccessor类,所以parseMetaElements传的参数是db.另外meta的保存截图如下

可以看出成员变量attributes是一个map类型,意味着一个bean里面可以拥有多个meta元素。而我们要删除某个attribute时,只需要把value置成空就好了, meta元素使用用例如下

7。 parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
这里主要是解析LOOKUP_METHOD_ELEMENT = "lookup-method"这个属性值,示例如下
8.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());这里用专门用来解析REPLACED_METHOD_ELEMENT = "replaced-method"这个属性值的,示例如下
9.parseConstructorArgElements(ele, bd);

这里主要是解析CONSTRUCTOR_ARG_ELEMENT = "constructor-arg"这个属性配置示例如下 :
10。 parsePropertyElements(ele, bd);

这里主要是解析PROPERTY_ELEMENT = "property"这个属性,先看下示例用法上面的示例是专门找的proxyfactorybean aop的配置。这里重点说下这个解析过程,因为很多自定义的成员内部变量的值注入就是在这里设置的。1)首先会找NAME_ATTRIBUTE = “name” 属性。必须要有不然就是个不合法的配置
2)这里直接把属性名push到LinkedList链表里
3)检查这个属性名是否已经存在,所以属性名要保证唯一性。不然数据不会被加载到内存
4)获取property 属性里面其它的内容,函数截图如下。首先会检查有没有description子元素
然后会检查没有有ref 和 value 属性 。 然后一般情况下ref和value是不应该同时存在的
如果有ref 属性,则返回RuntimeBeanReference对象,可以通过getBeanName获取具体内容。反射注入的时候用到
如果有value属性,则返回TypedStringValue对象。可以通过getValue获取具体内容。反射注入的时候用到
不管返回的是什么对象,我们关心的属性里面的具体内容已经得到。
然后就是解析这个property里面是不是有meta信息了,parseMetaElements(ele, pv);
然后就是保存数据了, bd.getPropertyValues().addPropertyValue(pv); 最终是保存在list里面,看具体实现


根据property name字段来判断里面是不是已经存在,如果存在则用新的数据重写,否则添加到list

11 . parseQualifierElements(ele, bd);

这个是解析QUALIFIER_ELEMENT = “qualifier” 这个属性,示例如下:
到这里差不多就快结束了,最后有两个setSource的调用。
bd.setResource(this.readerContext.getResource()); //这个设置资源文件这个好理解
bd.setSource(extractSource(ele)); //这个调用extractSource函数我找了半天,全是调用栈。干实事的就一个也是醉了。这个好像到最后返回的就是传进去的参数本身。类型强转为Object,不知道理解对不对。

单个bean的配置解析完成了,然后就是注册到hashmap上面去。

spring xml解析详解相关推荐

  1. Spring XML配置文件详解

    ​ spring配置文件是用于指导Spring工厂进行Bean生产.依赖关系注入(装配)及Bean实例分发的"图纸".Spring框架的配置文件是基于xml的,Spring强大的功 ...

  2. mapper注解的主要作用_Mybatis中mapper的xml解析详解

    上一篇文章分析了mapper注解关键类MapperAnnotationBuilder,今天来看mapper的项目了解析关键类XMLMapperBuilder. 基础介绍 回顾下之前是在分析config ...

  3. 解析xml_Mybatis中mapper的xml解析详解

    上一篇文章分析了mapper注解关键类MapperAnnotationBuilder,今天来看mapper的项目了解析关键类XMLMapperBuilder. 基础介绍 回顾下之前是在分析config ...

  4. android XML解析详解(封装好的工具类)

    常见的XML解析有哪几种? DOM解析; PULL解析;(android自带的解析XML的技术) JDOM解析; SAX解析; DOM4J PULL解析示例代码: <1> 我们要解析的XM ...

  5. Python之XML解析详解

    什么是XML? XML 指可扩展标记语言(eXtensible Markup Language). XML 被设计用来传输和存储数据. XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这 ...

  6. Java中Xml解析详解 DOM、SAX、JDOM、DOM4J

    1.1 什么是XML 一种表示结构化信息的标准方法,以使计算机能够方便地使用此类信息,并且人们可以非常方便地编写和理解这些信息.XML 是 eXtensible Markup Language(可扩展 ...

  7. 【JAVA秘籍心法篇-Spring】Spring XML解析源码详解

    [JAVA秘籍心法篇-Spring]Spring XML解析源码详解 所谓天下武功,无坚不摧,唯快不破.但有又太极拳法以快制慢,以柔克刚.武功外式有拳打脚踢,刀剑棍棒,又有内功易筋经九阳神功.所有外功 ...

  8. java bip-39_Java中对XML的解析详解

    先简单说下前三种方式: DOM方式:个人理解类似.net的XmlDocument,解析的时候效率不高,占用内存,不适合大XML的解析: SAX方式:基于事件的解析,当解析到xml的某个部分的时候,会触 ...

  9. php xml 实例教程,php解析xml方法实例详解,解析xml实例详解_PHP教程

    php解析xml方法实例详解,解析xml实例详解 本文以实例形式详细讲述了php解析xml方法.分享给大家供大家参考.具体分析如下: books.xml文件如下: Harry Potter J K. ...

  10. mybatis 同名方法_MyBatis(四):xml配置详解

    目录 1.我们将 数据库的配置语句写在 db.properties 文件中 2.在 mybatis-configuration.xml 中加载db.properties文件并读取 通过源码我们可以分析 ...

最新文章

  1. 使用java.util.Timer来周期性的执行制定的任务
  2. 在jmeter测试中模拟不同的带宽环境
  3. 使用PWM实现语音播放
  4. 做公益的飞秋(FeiQ)程序代码
  5. 80%程序员不知道的职场秘诀,升职加薪不是梦
  6. QQ客户端聊天窗口输入/自动变成表情 - 解决方案
  7. 【Java】URL下载网络资源(CloudMusic)
  8. Magic Trackpad 2 on win10 x64
  9. redis 删除操作命令
  10. 使用three建立一个正方体
  11. MFC实现FTP客户端
  12. C++编程 学习笔记(六)函数(续)
  13. 简单的Dos命令/一行代码实现恶意程序
  14. 软件架构---微核架构
  15. 二进制数的补码及运算
  16. 自动化测试之:python+unittest+selenium
  17. 自学python入门训练营 李笑来_1901090043-自学训练营学习9群-PYTHON入门
  18. Dev-C++ 实用安装教程
  19. 动态磁盘和基本磁盘的区别
  20. 2020湖南省技能竞赛获奖名单_2020年湖南省职业院校技能竞赛学院获奖情况通报...

热门文章

  1. 【Arduino创意】基于蜂鸣器制作摩尔斯电码生成器
  2. 初学者:set/multisetmap/multimap
  3. 数字化转型建设的基本模型与能力构建
  4. 【利用VBA批量处理中望CAD的修改打印出PDF】
  5. java事务和分布式事务详解
  6. 【第三方互联】2、创建腾讯QQ互联应用
  7. 电商业务中的五大机器学习问题!
  8. Win10使用以前的图片查看器
  9. 关于区块链你了解多少,用思维导图带你快速了解区块链
  10. Windows错误“ 0xc0000005”