Spring框架XML启动过程详解(二):解析BeanDefinition

本文详细讲解了Spring框架解析bean.xml文件的过程。从入口开始,调用XmlBeanDefinitionReader加载文件,经一系列方法解析为Document。解析流程包括元素解析、自定义标签装饰、BeanDefinition注册和可扩展监听器。最后梳理了整个解析过程,展现了Spring框架的设计思路和架构。

本文主要讲解此段代码在Spring框架中的解析过程,第二步正式开始解析XML文件并将解析结果放入BeanDefinition中的过程。

1.入口

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

如下图所示,在进入XmlBeanFactory的构造方法之后,会调用XmlBeanFactory自带的XmlBeanDefinitionReader来对XML文件进行加载,之前也提到过,XmlBeanFactory与其父类最大的不同的个性化实现就是增加了XmlBeanDefinitionReader类型的Reader来对资源文件进行读取和注册。

经过一系列的loadBeanDefinitions->doLoadBeanDefinitions->registerBeanDefinitions->doRegisterBeanDefinitions之后,最终将XML文件解析成为一个Document,并交给DefaultBeanDefinitionDocumentReader这样一个DocumentReader实现类来进行真正的解析,这里我们也可以了解到Spring框架解析的逻辑,一般而言,XXX方法都不是真正的处理方法,它只负责真正处理前的一些准备工作,doXXX方法才是的处理方法,当然这只是经验之谈。

在DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions方法中我们看到在真正的解析方法前和方法后分别有一个pre和post方法,如果你点进去可以发现这两个方法的方法体是空的,其实这两个方法是为了方便程序员扩展DefaultBeanDefinitionDocumentReader类,子类继承之后可以扩展这两个方法,增加一些自己独特的实现,这是模板方法模式的一种体现。

另外我们还可以看到在parseBeanDefinitions方法中,传入了一个新的参数delegate,往上看可以发现是BeanDefinitionParserDelegate类,看名字可以发现PareserDelegate 解析委托,它的作用就是辅助解析BeanDefinition,XML文件在经过Reader的解析和转换后成为Document对象,在Document当中存在一个个的element,每个element对应一个BeanDefinition,BeanDefinitionParserDelegate就负责对这些element进行解析

2.解析流程

接下来我们进入真正的解析方法中看一看,在经过parseBeanDefinitions之后是一个for循环,根据是默认的bean还是自定义的走两个不同的方法,这里选择默认的bean的处理方法parseDefaultElement,进去以后可以看见四个根据标签的判断,直接看第三个对bean标签的处理即可,最后我们到了真正的解析方法,如下图所示,共分为四个部分,下面我们一一对这几行代码进行解析。

2.1元素解析

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

这条代码主要用于解析bean.xml中的id、name等各种属性到BeanDefinition实例里,并将其封装到BeanDefinitionHolder当中,主要内容包括:

  1. 提取元素中的id以及name属性

  1. 解析所有属性并统一封装至GenericBeanDefinition实例中

  1. 若bean没有指定beanName,使用默认规则生成一个beanName

  1. 将获取到的信息封装到BeanDefinitionHolder实例中

2.2自定义标签装饰

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

Spring的bean属性配置主要有两类,默认标签配置属性和自定义标签配置属性,这条代码主要针对用户自定义的属性进行解析,主要内容包括:

  1. 获取属性或元素的命名空间来判断该元素或属性是否适用于自定义标签解析条件

  1. 根据命名空间找出自定义类型对应的NamespaceHandler处理器

  1. 对BeanDefinition进行修饰

2.3BeanDefinition注册

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

在对BeanDefinition进行解析和装饰之后,已经基本满足使用要求了,但是最后我们还需要对其进行注册,即这行代码做的事情,将解析装饰完的BeanDefinition注册到BeanDefinitionRegistry实例当中,主要内容包括:

  1. 注册前最后对BeanDefinition的methodOrerrides属性进行校验

  1. 如果对应的BeanName已经注册且在配置中配置了bean不允许被覆盖,则抛出异常

  1. 加入map缓存

  1. 清除解析之前留下的对应beanName的缓存

  1. 如果有别名,对别名进行注册

2.4可扩展监听器

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

到这里针对Bean.xml的解析基本已经结束了,在最后Spring框架还为我们留下了一段代码供扩展,当程序开发人员需要对注册BeanDefinition事件进行监听时可以通过注册监听器的方式将处理方式写入监听器中,目前Spring中并未对此事件做任何逻辑处理。

总结

在本文中,我们对Spring框架如何将bean.xml文件解析进内存和如何将其解析为可使用的BeanDefinition实例的整个过程做了一个梳理,在过程中我们可以窥探到Spring框架设计的一些思路和架构,组件间相互协调,一步步的深入其中,由Factory到Reader再到Holder最后经过Register,通过这些组件的配合,成功将BeanDefinition组装起来等待调用,组装完成之后,下一节我们会将Bean加载的过程进行一个详细的解析。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值