spring 之 BeanDefinition & BeanDefinitionParser
xml bean factory 的解析过程的 堆栈大概是这样的:
at org.springframework.beans.factory.xml.NamespaceHandlerSupport.findParserForElement(NamespaceHandlerSupport.java:)
at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:)
- locked <0x509> (a java.lang.Object)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:)
at AnnoIoCTest.main(AnnoIoCTest.java:)
可见,spring xml 文件的解析 基本是由 XmlBeanDefinitionReader 完成的。
bean 在代码层面的定义, 其实可以是非常丰富的。 最常见的, 当然就是 xml 文件中的 bean 元素了吧。
如果考虑下注解, 那么很快可以想起 @Bean , 这个注解也显而易见的 定义了一个bean。除此之外呢? 其实还有很多, 不那么明显的:
有各种各样的 bean 的定义格式, 那么, 相应的, 肯定存在各种各样的 bean 定义格式的 parser。
BeanDefinitionParser , 顾名思义, 就是对命名空间 bean 的定义的解析器 :

XmlBeanDefinitionReader 有一个 documentReaderClass 默认就是DefaultBeanDefinitionDocumentReader , 要求所有的实现必须是其子类。
BeanDefinitionParser 是spring 必须要加载的 默认的 bean 定义解析器。
DefaultBeanDefinitionDocumentReader 源码:
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
if(this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute("profile");
if(StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if(this.logger.isInfoEnabled()) {
this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
}
return;
}
}
}
this.preProcessXml(root);
this.parseBeanDefinitions(root, this.delegate);
this.postProcessXml(root);
this.delegate = parent;
}
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);// 可见, 默认是BeanDefinitionPeraserDelegation
delegate.initDefaults(root, parentDelegate);
return delegate;
}
这里的 delegate 默认就是 BeanDefinitionPeraserDelegation , 这是整个spring 的解析的 目前来说的 唯一的 入口 , 它是非常非常重要的。最关键当然是 parseBeanDefinitions方法, 接着看:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if(delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for(int i = ; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if(node instanceof Element) {
Element ele = (Element)node;
if(delegate.isDefaultNamespace(ele)) { // 默认命名空间就是 bean
this.parseDefaultElement(ele, delegate); // 处理默认的元素,也就是bean 元素, 实际是 交给 delegate 解析
} else {
delegate.parseCustomElement(ele); // 处理客户化定制的的元素, 这里的客户其实并不是我们定制的, 而是spring 定制的那些,比如contex,tx 等其他的命名空间
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
而parseCustomElement 就是读取 那个命名空间,然后从 spring.handlers 找到对应的 handler 类, 然后 解析它, 同时把解析解析结果 注册到 当前上下文 , 也就是 listabelbeanFactory。
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = this.getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if(handler == null) {
this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
} else {
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
这里的 handler 其实是 NamespaceHandlerSupport , 寻找实际的 parser , 是在其中这个方法中完成的:
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element); // 这里, 又调用了 delegate,
BeanDefinitionParser parser = (BeanDefinitionParser)this.parsers.get(localName); // NamespaceHandler 注册了很多的 parser
if(parser == null) {
parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
返回的parser 是 对某个命名空间下的 某个 类型bean 的 解析器, 比如 context 命名空间下的 component-scan , 对应 ComponentScanBeanDefinitionParser 等等以此类推。
public class ContextNamespaceHandler extends NamespaceHandlerSupport
{
public void init()
{
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
component-scan 元素 对应 的ComponentScanBeanDefinitionParser 就是其中一个。
property-placeholder 对应 PropertyPlaceholderBeanDefinitionParser, 很明显, 实际是实例化并 注册了一个 PropertySourcesPlaceholderConfigurer
BeanDefinitionParser 接口, 其实就一个 方法:
public interface BeanDefinitionParser {
BeanDefinition parse(Element var1, ParserContext var2);
}
parse 方法的作用是 , 解析那个element, 然后向 ParserContext 注册。
参考:
http://blog.csdn.net/wenjiangchun/article/details/50629764
spring 之 BeanDefinition & BeanDefinitionParser的更多相关文章
- spring 通过beanDefinition注册自定义规则的bean
目的: 扫描某个自定义注解标注的类, 或者自定义xml 为这些类生成spring Bean 基本原理:org.springframework.beans.factory.support.Default ...
- Spring:BeanDefinition&PostProcessor不了解一下吗?
水稻:这两天看了BeanDefinition和BeanFactoryPostProcessor还有BeanPostProcessor的源码.要不要了解一下 菜瓜:six six six,大佬请讲 水稻 ...
- Spring IoC BeanDefinition 的加载和注册
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 容 ...
- Spring组件BeanDefinition 源码解析
BeanDefinition 继承图 继承的接口 BeanMetadataElement接口 将由承载配置源对象的bean元数据元素的类实现. 包含一个getSource的方法,可以获取到MetaDa ...
- Spring源码系列 — BeanDefinition
一.前言 回顾 在Spring源码系列第二篇中介绍了Environment组件,后续又介绍Spring中Resource的抽象,但是对于上下文的启动过程详解并未继续.经过一个星期的准备,梳理了Spri ...
- 使用 BeanDefinition 描述 Spring Bean
什么是BeanDefinition 在Java中,一切皆对象.在JDK中使用java.lang.Class来描述类这个对象. 在Spring中,存在bean这样一个概念,那Spring又是怎么抽象be ...
- Spring官网阅读(四)BeanDefinition(上)
前面几篇文章已经学习了官网中的1.2,1.3,1.4三小结,主要是容器,Bean的实例化及Bean之间的依赖关系等.这篇文章,我们继续官网的学习,主要是BeanDefinition的相关知识,这是Sp ...
- 深入Spring之IOC之加载BeanDefinition
本文主要分析 spring 中 BeanDefinition 的加载,对于其解析我们在后面的文章中专门分析. BeanDefinition 是属于 Spring Bean 模块的,它是对 spring ...
- Spring中眼花缭乱的BeanDefinition
本篇博客主要参考:Spring官网阅读(四)BeanDefinition(上) 引入主题 为什么要读Spring源码,有的人为了学习Spring中的先进思想,也有的人是为了更好的理解设计模式,当然也有 ...
随机推荐
- Codeforces Round #324 (Div. 2) (哥德巴赫猜想)
题目:http://codeforces.com/problemset/problem/584/D 思路: 关于偶数的哥德巴赫猜想:任一大于2的偶数都可写成两个素数之和. 关于奇数的哥德巴赫猜想:任一 ...
- Codeforces Round #207 (Div. 1) A. Knight Tournament (线段树离线)
题目:http://codeforces.com/problemset/problem/356/A 题意:首先给你n,m,代表有n个人还有m次描述,下面m行,每行l,r,x,代表l到r这个区间都被x所 ...
- python小知识——__name__ = '__main__' 的作用
很多新手刚开始学习python的时候经常会看到python 中__name__ = \'__main__\' 这样的代码,可能很多新手一开始学习的时候都比较疑惑,python 中__name__ = ...
- postman之如何获取cookie
1.最近在学习postman的使用方法,为了保证后续模块操作,必须在登录时获取的session值,并将其设置为环境变量,session的位置处于response headers里面返回的set-coo ...
- vue中使用axios给生产环境和开发环境配置不同的baseUrl
第一步:设置不同的接口地址 找到文件:/config/dev.env.js 代码修改为: var merge = require('webpack-merge') var prodEnv = requ ...
- js 判断是否可以打开本地软件
js判断时候可以打开本地的软件或者插件 点击一个按钮,打开本地的软件,比如问题反馈,需要调起本地的邮箱,填入一些信息. 这个功能<a>标签有提供支持,但是如果本地没有安装邮箱,则无法打开, ...
- spring aop无法拦截类内部的方法调用
1.概念 拦截器的实现原理就是动态代理,实现AOP机制.Spring 的代理实现有两种:一是基于 JDK Dynamic Proxy 技术而实现的:二是基于 CGLIB 技术而实现的.如果目标对象实现 ...
- JS Replace 全部替换字符的用法小结
script language="javascript">var r= "1\n2\n3\n";//将字母\n替换成分号alert(r.replace(& ...
- 使用pageoffice进行多个文档的合并
提前给test模板文件中 手动插入一个书签,因为pageoffice必须有一个书签后,才能在后台进行书签的创建 //多个word文件进行合并 string strCopyFolder = System ...
- SQL 语句 explain 分析
分析索引的效率: > EXPLAIN sql; EXPLAIN 分析的结果的表头如下: id | select_type | table | partitions | type | poss ...