Spring中 bean定义的parent属性机制的实现分析
<bean id="transactionProxy01" parent="transactionProxy1">
<property name="target" ref="service01"/>
</bean> <bean id="transactionProxy1" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,timeout_6000,-Exception</prop>
<prop key="error*">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_20,readOnly,-Exception</prop> <!-- -Exception表示有Exception抛出时,事务回滚. -代表回滚 +就代表提交 -->
</props>
</property>
</bean>
- 一个是解析xml创建出BeanDefinition对象,
- 一个是从beanFactory中 依据BeanDefinition创建出实例
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); //对xml中的bean元素挨个做解析
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//利用delegate的方法 解析出bean元素 beanDefinition对象存放在一个Holder里面
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
try {
//这个是注册 就是把BeanDefinition保存到BeanFactory的BeanDefinitionMap里面去
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
}
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE); //获取出bean的id
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//...省略了一些代码
String beanName = id;
//...省略了一些代码
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);//解析xml中的bean元素 创建beanDefinition对象
if (beanDefinition != null) {
//...省略了一些代码
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));//SAX解析特有的 都要定义一个stack做辅助
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE); //取出了parent属性的值
}
AbstractBeanDefinition bd = createBeanDefinition(className, parent);//创建一个BeanDefinition对象 注意把parent属性传进去了 //后面就是解析bean元素的其他属性 然后set到这个BeanDefinition对象里面去
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//...省略了一些代码
return bd;
}
//...省略了一些代码
finally {
this.parseState.pop();
}
return null;
}
进入BeanDefinitionReaderUtils工具类
public static AbstractBeanDefinition createBeanDefinition(
String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();//创建一个beanDefinition对象
bd.setParentName(parentName);//把parent属性set进去
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd; //然后返回beanDefinition对象
}
至此 BeanDefinition是创建完了 可以看到,我们定义parent属性,在创建过程中并没有什么特殊的处理,只是把parent作为一个属性,设置到BeanDefinition对象里面去了
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); //这里是根据beanName获取到BeanDefinition,parent的处理就是在这里发生的
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); //一开始获取合并的BeanDefinition 肯定是null 之前没有缓存的
if (mbd != null) {
return mbd;
}
//然后先取出原始的transactionProxy01的beanDefinition 注意 这里取出的beanDefinition中 beanName是transactionProxy01,parent是transactionProxy1,
//但是beanClass是null
//然后执行getMergedBeanDefinition(beanName, getBeanDefinition(beanName)) 准备把parent的beanClass属性拿出来放到子beanBefinition里面去
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
if (bd.getParentName() == null) {
//....省略一些代码
}
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());//取到parent的name
if (!beanName.equals(parentBeanName)) {
//这个方法获取parent对于的beanDefinition,这个方法里面其实又是调用上一个方法的
//也就是还是进一步调用getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); 是递归的! 用于解决parent还有parent 的情况
//所以这个地方要特别注意的 多层级的parent处理就是这里的递归解决的
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
//....省略一些代码
}
}
//....省略一些代码
// Deep copy with overridden values.
//核心的来了 先用parent 的BeanDefinition为参数,创建了一个新的BeanDefinition 想想都知道就是new了一个新的RootBeanDefinition对象
//然后把parent的BeanDefinition的属性一个一个都set到新的RootBeanDefinition对象里面,相当于深拷贝了
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);//然后用孩子beanDefinition已有的属性 去覆盖掉parent里继承下来的属性值
}
//....省略一些代码 }
return mbd;
}
}
至此,spring处理的parent的方式已经搞清楚了
<bean id="transactionProxy01" parent="transactionProxy1">
<property name="target" ref="service01"/>
</bean>
<bean id="transactionProxy1" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,timeout_6000,-Exception</prop>
<prop key="error*">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_20,readOnly,-Exception</prop>
</props>
</property>
</bean>
- 我们得到的mbd 就是这样一个BeanDefinition
- 它的beanName是transactionProxy01
- 它的target是service01
- 它的beanClass,以及其他的属性,都和parent的BeanDefinition是相同的
private final Map<String, RootBeanDefinition> mergedBeanDefinitions =
new ConcurrentHashMap<String, RootBeanDefinition>(64);
原创博客,转载请注明出处
Spring中 bean定义的parent属性机制的实现分析的更多相关文章
- spring中bean的配置详解--定义parent
在工作中碰到了好多的配置文件,具体来说是spring 中bean配置的parent的配置,搞的我一头雾水,仔细看一下spring中有关bean的配置,剖析一下,具体什么含义! 一.Spring IoC ...
- spring中bean的作用域属性singleton与prototype的区别
1.singleton 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会 ...
- Spring中bean标签的属性和值:
Spring中bean标签的属性和值: <bean name="user" class="com.pojo.User" init-method=" ...
- Spring 中bean的作用、定义
Spring 中bean的作用.定义: 创建一个bean定义,其实质是用该bean定义对应的类来创建真正实例的"配方(recipe)".把bean定义看成一个配方很有意义,它与cl ...
- 一次性讲清楚spring中bean的生命周期之三:bean是如何实例化的
在前面的两篇博文<一次性讲清楚spring中bean的生命周期之一:getSingleton方法>和<一次性讲清楚spring中bean的生命周期之二:FactoryBean的前世今 ...
- Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别
Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...
- Spring中bean的配置
先从IOC说起,这个概念其实是从我们平常new一个对象的对立面来说的,我们平常使用对象的时候,一般都是直接使用关键字类new一个对象,那这样有什么坏处呢?其实很显然的,使用new那么就表示当前模块已经 ...
- (转)Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别
Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...
- JAVA面试题:Spring中bean的生命周期
Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...
随机推荐
- 【转】Valid signing identity not found解决办法(原有IDP私钥丢失)及Certificate、App ID、Devices、Provisioning Profiles之间区别--不错
原文网址:http://blog.csdn.net/mad1989/article/details/8699147 前言: 刚刚把mini换成了macbookair,之前一直在mini上进行开发,到换 ...
- EasyUI的增删查改(后台ASP.NET)
转自:http://www.cnblogs.com/dedeyi/archive/2013/04/22/3035057.html 某某人曾经跟我说,你们做系统不就是增删查改吗. 是啊,很多时候我们就是 ...
- (转载)MySQL数据类型中DECIMAL的作用和用法
(转载)http://database.51cto.com/art/201005/201651.htm 在MySQL数据类型中,例如INT,FLOAT,DOUBLE,CHAR,DECIMAL等,它们都 ...
- Flash Vector例子
var s1:Student = new Student(); var s2:Student = new Student(); var s3:Student = new Student(); s1.n ...
- 开源库CImg 数据格式存储
CImg为开源图像处理库,仅有一个头文件CImg.h便包含了对图像的所有处理函数,函数操作简单,编程方便,但国内使用者较少 其homepage:http://cimg.sourceforge.net/ ...
- MFC中添加OpenGL
WINDOWS下展示OpenGL有多种形式: MFC 或 win32,该如何向MFC中添加OpenGL?下面是介绍最简单OpenGL框架. 1.首先通过VS建立MFC应用程序-MyOpenGL,选择单 ...
- bzoj3224 Tyvj 1728 普通平衡树(名次树+处理相同)
3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5354 Solved: 2196[Submit][Sta ...
- XPath在asp.net中查询XML -摘自网络
.NET Framework 2.0中可以使用System.Xml.XPath命名空间下的类对XML文档进行基于路径的查询,在查询过程中需要构造类似SQL的查询字符串,该字符串遵循XPath语法.它由 ...
- nyoj 116 士兵杀敌(二)【线段树单点更新+求和】
士兵杀敌(二) 时间限制:1000 ms | 内存限制:65535 KB 难度:5 描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军经常 ...
- oc学习之路-----搞死指针之内存存储int类型
关于每个数据类型个字节在内存中的存储地址(以int为例) 先上图 如题,为什么说好的*p = &c是1啊,为什么是513呢,一开始,我也觉得挺惊讶的,后面听老师分析了一下才知道怎么回事,但是还 ...