Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

时间:2021-07-04 10:58:59

写在前面

上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读取配置文件,将其经过编码并经过系列处理后,交给了同类中的doLoadBeanDefinitions()方法,这次就直接进入这个方法,来看看Spring到底是如何创建BeanDefinition的。


1.2 BeanDefinition的创建 - 创建BeanDefinition前的最终准备

首先进入XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法

Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

方法很简单

  • 创建XML文件的Document
  • 根据Doucment和InputSource加载BeanDefinition

Doucument对象是W3C定义的XML格式的规范,它的创建我不是很感兴趣,这里就不再讨论,如果有兴趣大家可以自行百度,研究一下。

而我们期待的重点被再次委托,进入registerBeanDefinitions(Document doc,Resource resource)方法。

Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

方法内部根据资源文件创建了一个XmlReaderContext后(不在我的关心范围内,跳过),被再次委托给BeanDefinitionDocumentReader接口中的同名方法,继续跟进。

Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

从Document获取Element后,看到下面的方法名就知道接下来我们要进入真正的Bean元素解析的阶段了。


1.3 BeanDefinition的创建 - 解析BeanDefinition

protected void doRegisterBeanDefinitions(Element root) {
//todo flash 不太懂这两个的变换是什么意思,以后有时间可以仔细研究一下
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
// 处理 profile 模式
if (this.delegate.isDefaultNamespace(root)) {
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)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 开始解析
// 解析前,交给子类自定义实现
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
// 解析后,交给子类自定义实现
postProcessXml(root); this.delegate = parent;
}

函数首先是处理profile,(关于这部分详尽的内容推荐这篇文章.)如果找不到对应的profile会直接跳过注册,结束方法。

preProcessXml()和postProcessXml()两个方法则是Spring留给外部拓展的方法,在Spring中与他们类似的方法有很多,我习惯性把它称为'前处理器''后处理器'

而'前处理器'和'后处理器'中间的这个方法就是Bean解析的方法了,进入此方法。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//判断是否是默认的命名标签
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//处理默认的标签
parseDefaultElement(ele, delegate);
}
else {
//处理自定义的标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}

Spring中的标签分为两种,一种是默认的(Spring官方的)

<bean id="student"  class="com.flash.springtest.dto.Student"/>

另一种则是我们自定义的

<!-- 看不懂就对了,所以是'自定义'标签 -->
<flash:stuednt key:com.flash.springtest.dto.Student>

如上,关于自定义标签的更多内容可以查看此篇文章,后续在解析自定义标签的环节中看心情要不要自己搞一搞。


这篇文章就先到这里,下篇将正式开始解析Spring的默认标签。