spring的生命周期里,其实并不只是在applicationContext上下文里get bd,就丢到单例池里,而是会进行一步mergeBeanDefinition操作,也就是合并BD

BeanDefnition(BD)是没有mergedBeanDefinition这个类型,它只是进行了个合并

为什么要合并beanDefinition,这是因为BD存在父子关系,这个可能是业务逻辑的需要吧,这个暂时不太明白哈。先debug看一段代码吧

public class TestSpring {public static void main(String[] args) {AnnotationConfigApplicationContextac = new AnnotationConfigApplicationContext();//把p类变成rootbd  作为一个父类,也可以作为一个正常RootBeanDefinition p = new RootBeanDefinition(P.class);//给p的bd设置了一些属性  scope=prototypep.setScope(AbstractBeanDefinition.SCOPE_PROTOTYPE);//实例化一个childbd,这个bd继承了名字为p的bdChildBeanDefinition c = new ChildBeanDefinition("p");//再把这个bd去关联C类c.setBeanClass(C.class);//往bdmapd当中添加bdac.registerBeanDefinition("p",p);ac.registerBeanDefinition("c",c);ac.refresh();System.out.println("");}
}

断点打在了        System.out.println("");这里可以看看这段代码,将子bd继承父bd都register到ioc容器里,再refresh,看看

仔细看看这两个map有什么区别?一般我们都认为bd都是存放在beanDefinitionMap里面,但事实上并不是这样的,在spring中,会有一个mergedBeanDefnitions来存放合并后的bd,而什么是合并后的bd呢,可以看看上面图这两个的区别,除了c,在代码中定义为Childbd的类,从Childbd,变成了Rootbd,其他原本是Rootbd的就没发生改变。

那么这是在啥时候发生改变的呢?

不晓得大家有没有看我写的clearByTypeCache的文章里的getBeanNamesForType方法的解析。看了就应该知道,里面有个doGetBeanNamesForType这个方法

 private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {List<String> result = new ArrayList<>();// Check all bean definitions.for (String beanName : this.beanDefinitionNames) {// Only consider bean as eligible if the bean name is not defined as alias for some other bean.if (!isAlias(beanName)) {try {//先合并,再put到mergedBeanDefinitionmap当中,然后返回RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

里面就会调用这个getMergedLocalBeanDefinition方法,得到一个RootBeanDefinition对象,点进去看看

 protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {// Quick check on the concurrent map first, with minimal locking.RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);if (mbd != null && !mbd.stale) {return mbd;}return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));}

可以看到,也是从这个mergedBeanDefinitions  map里找,找不到再调用下面这个方法,

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)throws BeanDefinitionStoreException {synchronized (this.mergedBeanDefinitions) {RootBeanDefinition mbd = null;RootBeanDefinition previous = 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 || mbd.stale) {previous = mbd;//如果childbd  c的ParentName为空//表示是一个父类,或者普通类,就直接返回RootBeanDefinition,不会走下面else的逻辑,也会放到mergedBeanDefinitions里面if (bd.getParentName() == null) {// Use copy of given root bean definition.if (bd instanceof RootBeanDefinition) {mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();}else {mbd = new RootBeanDefinition(bd);}}else {// Child bean definition: needs to be merged with parent.//定义一个bd来接收父bdBeanDefinition pbd;try {String parentBeanName = transformedBeanName(bd.getParentName());if (!beanName.equals(parentBeanName)) {pbd = getMergedBeanDefinition(parentBeanName);}else {BeanFactory parent = getParentBeanFactory();if (parent instanceof ConfigurableBeanFactory) {pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);}else {throw new NoSuchBeanDefinitionException(parentBeanName,"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +"': cannot be resolved without a ConfigurableBeanFactory parent");}}}catch (NoSuchBeanDefinitionException ex) {throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);}// Deep copy with overridden values.//把父bd赋给这个mbdmbd = new RootBeanDefinition(pbd);//再把子bd覆盖mbdmbd.overrideFrom(bd);}// Set default singleton scope, if not configured before.if (!StringUtils.hasLength(mbd.getScope())) {mbd.setScope(SCOPE_SINGLETON);}// A bean contained in a non-singleton bean cannot be a singleton itself.// Let's correct this on the fly here, since this might be the result of// parent-child merging for the outer bean, in which case the original inner bean// definition will not have inherited the merged outer bean's singleton status.if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {mbd.setScope(containingBd.getScope());}// Cache the merged bean definition for the time being// (it might still get re-merged later on in order to pick up metadata changes)if (containingBd == null && isCacheBeanMetadata()) {this.mergedBeanDefinitions.put(beanName, mbd);}}if (previous != null) {copyRelevantMergedBeanDefinitionCaches(previous, mbd);}return mbd;}}

可以看看这个方法,合并的逻辑都在里面,可以看到,不管是父bd(普通bd)还是子bd,都会进行里面的逻辑,只不过不同,父bd就直接copy或者返回Rootbd了,而子bd就要进行里面的合并逻辑,然后再经过

//把父bd赋给这个mbd
                    mbd = new RootBeanDefinition(pbd);
                    //再把子bd覆盖mbd
                    mbd.overrideFrom(bd);

进行真正的合并。

最后都put到mergedBeanDefnitions里

mergedBeanDefinition相关推荐

  1. 合并的bean定义 - MergedBeanDefinition

    我们通过获取bean,来看看如何 "合并BeanDefinition",BeanDefinition在获取bean过程中的作用 "合并BeanDefinition&quo ...

  2. 使用Spring框架的好处

    转自:https://www.cnblogs.com/hoobey/p/6032506.html 在SSH框假中spring充当了管理容器的角色.我们都知道Hibernate用来做持久层,因为它将JD ...

  3. java单例注册表_Spring对单例的底层实现,单例注册表

    public abstract class AbstractBeanFactory implementsConfigurableBeanFactory{/*** 充当了Bean实例的缓存,实现方式和单 ...

  4. 框架:spring总结

    struts 是 web 框架 (jsp/action/actionfrom)  hibernate 是 orm框架,处于持久层. 那么,什么是Spring? spring 是容器框架,用于配置bea ...

  5. Spring加载流程源码

    一.从AbstractApplicationContext的体系说起 第一,从类结构设计上看, 围绕着是否需要Refresh容器衍生出两个抽象类: GenericApplicationContext: ...

  6. spring的InitializingBean介绍

    http://blog.csdn.net/hhdem/article/details/1802701 InitializingBean Spirng的InitializingBean为bean提供了定 ...

  7. 单例模式不能被继承_Spring的单例实现原理

    单例模式有饿汉模式.懒汉模式.静态内部类.枚举等方式实现,但由于以上模式的构造方法是私有的,不可继承,Spring为实现单例类可继承,使用的是单例注册表的方式. 什么是单例注册表呢: Spring是通 ...

  8. Spring的bean定义 2 : 通用bean定义逻辑 -- AbstractBeanDefinition

    概述 AbstractBeanDefinition是最终全功能BeanDefinition实现类的基类,也就是这些类的共同属性和公共逻辑实现. AbstractBeanDefinition中并没有太复 ...

  9. java spring ioc 实例_Spring 源码阅读(IOC容器)-bean的实例化以及注入

    3.Bean的实例化以及注入过程分析 Bean的实例以及注入是在getBean时触发的,由于外部容器是与外部调用交互的桥梁,我们首先从外部容器入手,AbstractApplicationContext ...

最新文章

  1. Python五种常见的算法,你都了解么
  2. 【Android 逆向】IDA 工具使用 ( IDA 32 位 / 64 位 版本 | 汇编代码视图 IDA View-A | 字符串窗口 Strings window )
  3. VMware网络连接模式—桥接、NAT以及仅主机模式的详细介绍和区别.ziw
  4. 回复群邮件导致邮件服务器,电子邮件逐个发-邮件群发软件-使用手册
  5. 解决SurfaceView渲染的各种疑难杂症
  6. C# 10 新特性 —— CallerArgumentExpression
  7. Shell else if mysql_linux shell中 if else以及大于、小于、等于逻辑表达式介绍
  8. 基于JAVA+SpringBoot+Mybatis+MYSQL的图书管理系统
  9. Ubuntu安装MyEclise16 过程差不多
  10. web myeclipse为什么连接不上css_好程序员web前端培训分享:web前端自学该怎么规划学习...
  11. 通过抓包工具抓包APP就连不上网的解决方案
  12. 2018 阿里 声学模型 语言模型
  13. apple tv 开发_如何在Apple TV上播放计算机中的视频文件
  14. 三菱plc 与 计算机 通讯,三菱FX系列PLC和PC的通讯联接
  15. auto.js B0012 进入各频道 查找父控件 子控件 2021-10-03
  16. 数据库大作业-电影院管理系统
  17. 信息系统项目管理师 第七章-项目成本管理
  18. RVV线与RV线有什么区别
  19. Goby内测版1.8.292|后台扫描、导出截图等功能上线(文末福利等你~)
  20. 联合循环—25(了解PID原理图1)

热门文章

  1. ipad视频导入重新命名排序
  2. win10文件后缀名怎么显示_怎么把win7文件名都显示出来
  3. 金山武汉总部园区来了!拟2024年竣工 可容纳员工9000人
  4. java ubb_月光软件站 - 编程文档 - Java - JAVA写的简单UBB类
  5. Python学习笔记8——数据类型(下)
  6. Android Studio编辑光标变粗的解决方法
  7. java怎么读取db文件,java怎么连接db数据库文件
  8. qq好友列表获取之动态爬虫清洗爬取好友列表数据 - 获取qq好友、群、群成员列表
  9. 为什么公共关系应该在您的社交媒体营销中发挥作用
  10. ​​​​​​​Oracle学习详解02版