【死磕 Spring】----- IOC 之 注册 BeanDefinition
原文出自:http://cmsblogs.com
获取 Document 对象后,会根据该对象和 Resource 资源对象调用 registerBeanDefinitions() 方法,开始注册 BeanDefinitions 之旅。如下:
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;
}
首先调用 createBeanDefinitionDocumentReader() 方法实例化 BeanDefinitionDocumentReader 对象,然后获取统计前 BeanDefinition 的个数,最后调用 registerBeanDefinitions() 注册 BeanDefinition。
实例化 BeanDefinitionDocumentReader 对象方法如下:
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
注册 BeanDefinition 的方法 registerBeanDefinitions() 是在接口 BeanDefinitionDocumentReader 中定义,如下:
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
throws BeanDefinitionStoreException;
从给定的 Document 对象中解析定义的 BeanDefinition 并将他们注册到注册表中。方法接收两个参数,待解析的 Document 对象,以及解析器的当前上下文,包括目标注册表和被解析的资源。其中 readerContext 是根据 Resource 来创建的,如下:
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
DefaultBeanDefinitionDocumentReader 对该方法提供了实现:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
调用 doRegisterBeanDefinitions() 开启注册 BeanDefinition 之旅。
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
// 处理 profile
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主要用于我们切换环境,比如切换开发、测试、生产环境,非常方便。然后调用 parseBeanDefinitions() 进行解析动作,不过在该方法之前之后分别调用 preProcessXml() 和 postProcessXml() 方法来进行前、后处理,目前这两个方法都是空实现,交由子类来实现。
protected void preProcessXml(Element root) {
}
protected void postProcessXml(Element root) {
}
parseBeanDefinitions() 定义如下:
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);
}
}
最终解析动作落地在两个方法处:parseDefaultElement(ele, delegate) 和 delegate.parseCustomElement(root)。我们知道在 Spring 有两种 Bean 声明方式:
- 配置文件式声明:
<bean id="studentService" class="org.springframework.core.StudentService"/> - 自定义注解方式:
<tx:annotation-driven>
两种方式的读取和解析都存在较大的差异,所以采用不同的解析方法,如果根节点或者子节点采用默认命名空间的话,则调用 parseDefaultElement() 进行解析,否则调用 delegate.parseCustomElement() 方法进行自定义解析。
至此,doLoadBeanDefinitions() 中做的三件事情已经全部分析完毕,下面将对 Bean 的解析过程做详细分析说明。
【死磕 Spring】----- IOC 之 注册 BeanDefinition的更多相关文章
- 死磕Spring之IoC篇 - BeanDefinition 的加载阶段(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - BeanDefinition 的解析阶段(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - BeanDefinition 的解析过程(面向注解)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程
原文出自:http://cmsblogs.com import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程. 在方法 parseDefaultElement ...
- 【死磕 Spring】—– IOC 之解析Bean:解析 import 标签
原文出自:http://cmsblogs.com 在博客[死磕Spring]----- IOC 之 注册 BeanDefinition中分析到,Spring 中有两种解析 Bean 的方式.如果根节点 ...
- 【死磕 Spring】----- IOC 之 加载 Bean
原文出自:http://cmsblogs.com 先看一段熟悉的代码: ClassPathResource resource = new ClassPathResource("bean.xm ...
- 死磕Spring之IoC篇 - 解析自定义标签(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - 开启 Bean 的加载
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - Bean 的创建过程
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - @Autowired 等注解的实现原理
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
随机推荐
- jQuery 素材 缩略图轮播集合
http://www.17sucai.com/pins/demo-show?id=27124 http://www.17sucai.com/pins/demo-show?id=4712 楼盘详情缩略 ...
- 推荐《用Python进行自然语言处理》中文翻译-NLTK配套书
NLTK配套书<用Python进行自然语言处理>(Natural Language Processing with Python)已经出版好几年了,但是国内一直没有翻译的中文版,虽然读英文 ...
- Http Hijacker
- Python Redis 的安装
安装 可以去pypi上找到redis的Python模块: http://pypi.python.org/pypi?%3Aaction=search&term=redis&submit= ...
- 关于Google 圆角 高光 高宽 自适应 按钮
最近看了张鑫旭老师关于Google搜索按钮的博客,感觉启示颇多.下面我就详说一下这个按钮的代码,由于W3C新版本的更新,之前的代码会有部分累赘, 在此,我做了些修改.当然,想观摩原版的可以,狠狠的戳链 ...
- pip 安装mysqlclient报错OSError: mysql_config not found
执行 pip install mysqlclient 报错信息如下: [root@CentOS7-demo bin]# pip install mysqlclient Collecting mysql ...
- vs插件-基于TFS的源码记录可视化
插件地址:https://marketplace.visualstudio.com/items?itemName=AlexandrBiryukov.TFSSourceControlHistoryVis ...
- classpath和filepath
******************************** java中的相对路径和绝对路径 ******************************** 相对路径(其实就是编译后的路径) - ...
- Error【0002】:YUM本地源配置问题
1.1 问题背景 通过VMware workstation创建虚拟机,在虚拟机的CDROM设备中,装载操作系统镜像.然后通过mount -o loop的方式,将CDROM设备挂载到系统的/mnt/cd ...
- php之array_column 的使用
听说只有大牛级的高工才知道的函数array_column () 讲真,我才知道. (PHP 5 >= 5.5.0, PHP 7) array_column - 返回数组中指定的一列 说明 arr ...