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的别名只能维持一 ...
随机推荐
- 【HDOJ】4183 Pahom on Water
就是一个网络流.red结点容量为2,查看最大流量是否大于等于2.对于条件2,把边反向加入建图.条件1,边正向加入建图. /* 4183 */ #include <iostream> #in ...
- Unity3D之资源问题处理
你做的东西如果是100%完整版 你就用 流媒体资源 Streaming Assets http://game.ceeger.com/Manual/StreamingAssets.html 你如果是类微 ...
- android开发板
element14-beaglebone-black http://www.embest-tech.cn/shop/star/element14-beaglebone-black-rev-c.html ...
- Devexpress 之gridControl
1.gridControl如何去掉主面板? 鼠标右键Run Designer=>OptionsView => ShowGroupPanel=False: 2.gridControl如何设置 ...
- EF框架搭建
EF框架搭配lambda表达式使用起来非常高效便捷,有两种方法使用EF框架: 一是.添加“ADO.NET Entity Data Model”项,绑定配置数据库链接,勾选表和存储过程等,自动生成实体: ...
- 向Git证明自己的身份,Git别名配置
一.向Git证明自己的身份 在安装完Git后,第一步就是向Git说明自己的身份,通过如下两个命令证明: git config --global user.name "myusername&q ...
- [JLOI2013]卡牌游戏
[题目描述 Description] N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡 ...
- Linux I2C设备驱动编写(一)
在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即I2C适配器 I2C driver 某个I2C设备的设备驱动,可以以driver理解. I2C client 某个I2C ...
- (转)解决png图片在IE6下不透明的方法
来源于:http://xzl52199.blog.163.com/blog/static/95206446201142174540220/ 一.传统的JavaScript方法 思路: 1.一个专门解决 ...
- 【C#】与C及OC的不同点
事实上熟悉这些语言的朋友们深知,这几个语言全然没有可比性. 因为工作须要,近期须要重温C#语言,难免会受到C和OC的基础知识影响. 此篇是本人的一个学习笔记.仅此献给有C/OC基础,须要继续学习C# ...