在Spring源码系列:BeanDefinition载入(上)中已经大概捋了一下解析过程,本篇将记录一下bean的注册过程。

bean的注册就是DefaultListableBeanFactory中registerBeanDefinition方法来完成的。那我就来看registerBeanDefinition这个方法的具体逻辑。

1、beanDefinition类型判断和验证

这里的验证主要是验证不能将静态工厂方法与方法重写相结合(静态工厂方法必须创建实例);

if (beanDefinition instanceof AbstractBeanDefinition) {try {        ((AbstractBeanDefinition) beanDefinition).validate();    }catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(),        beanName,"Validation of bean definition failed", ex);    }}复制代码

2、尝试从beanDefinitionMap中获取老的bean

这里就是先根据beanName从beanDefinitionMap去取BeanDefinition,并将结果给oldBeanDefinition。

BeanDefinition oldBeanDefinition;oldBeanDefinition = this.beanDefinitionMap.get(beanName);复制代码

3、beanDefinitionMap中已经存在名为beanName的Beandefinition

如果当前beanDefinitionMap中已经存在名为beanName的Beandefinition了(即检查是否有相同名称的beanDefinition已经在Ioc容器中注册过了)。,如果有,则进行以下具体策略:

  • 如果不允许bean被覆盖,则直接抛出不能重新注册,bean已经存在这样的异常信息
  • 使用框架生成的Bean来代替用户自定义的bean
  • 覆盖原有的Beandefinition
if (oldBeanDefinition != null) {if (!isAllowBeanDefinitionOverriding()) {//省略异常代码    }else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {//省略异常代码    }else if (!beanDefinition.equals(oldBeanDefinition)) {//提示覆盖log信息    }else {//提示覆盖log信息    }//覆盖原有的Beandefinitionthis.beanDefinitionMap.put(beanName, beanDefinition);}复制代码

4、beanDefinitionMap不存在名为beanName的Beandefinition

//检查bean的创建阶段是否已经开始,也就是说是否已经创建了if (hasBeanCreationStarted()) {//Cannot modify startup-time collection elements anymore (for stable iteration)// 无法修改启动时间收集元素(用于稳定迭代)(译注)//注册过程需要保证数据的一致性,所有需要加锁同步synchronized (this.beanDefinitionMap) {//注册到beanDefinitionMap中this.beanDefinitionMap.put(beanName, beanDefinition);//下面就是将当前beanName存放到beanDefinitionNames中        List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);        updatedDefinitions.addAll(this.beanDefinitionNames);        updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;//如果单例模式的bean名单中有该bean的name,那么移除掉它。//也就是说着,将一个原本是单例模式的bean重新注册成一个普通的beanif (this.manualSingletonNames.contains(beanName)) {            Set<String> updatedSingletons = new            LinkedHashSet<String>(this.manualSingletonNames);            updatedSingletons.remove(beanName);this.manualSingletonNames = updatedSingletons;        }    }}// 仍处于启动阶段,bean还没有开始注册else {// Still in startup registration phasethis.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}this.frozenBeanDefinitionNames = null;复制代码

5、执行缓存清除

  • 1:oldBeanDefinition如果存在,且执行到了这里也没有抛出异常,说明该BeanDefinition已经被覆盖,缓存需要更新。

  • 2:如果是单例模式的bean对象则Set中包含该beanName,执行到这里说明该BeanDefinition已经从一个单例模式的bean变为了一个普通的bean,所以缓存也需要更新。

if (oldBeanDefinition != null || containsSingleton(beanName)) {    resetBeanDefinition(beanName);}复制代码

OK,我们来看下resetBeanDefinition这个方法:

这个方法的作用就是重置给定bean的所有bean定义缓存,包括从它派生的bean的缓存。

protected void resetBeanDefinition(String beanName) {// 如果已经创建,则删除给定bean的合并bean定义。    clearMergedBeanDefinition(beanName);

// 如果有的话,从singleton 高速缓存中删除相应的bean。//但是这也不是必须的,而只是为了覆盖上下文的默认bean//(就是从manualSingletonNames中移除)    destroySingleton(beanName);//递归的方式来 重置具有给定bean作为父项的所有bean定义。for (String bdName : this.beanDefinitionNames) {if (!beanName.equals(bdName)) {            BeanDefinition bd = this.beanDefinitionMap.get(bdName);if (beanName.equals(bd.getParentName())) {                resetBeanDefinition(bdName);            }        }    }}复制代码

Bean的注册就到这里了,下一篇学习的是DefaultListableBeanFactory这个集大成者容器。

Spring源码系列:BeanDefinition载入(下)相关推荐

  1. Ioc容器beanDefinition-Spring 源码系列(1)

    Ioc容器beanDefinition-Spring 源码系列(1) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器 ...

  2. Spring源码系列:依赖注入(二)createBean

    在Spring源码系列:依赖注入(一)(AbstractBeanFactory-getBean)最后说道getBean是依赖注入的起点,bean的创建都是通过createBean来完成具体的创建的.c ...

  3. Spring源码系列(十二)Spring创建Bean的过程(二)

    1.写在前面 上篇博客主要Spring在创建Bean的时候,第一次调用的Bean的后置处理器的过程,同时笔者也打算将整个Spring创建的Bean的过程,通过这个系列,将Bean的创建过程给讲清楚,废 ...

  4. Spring源码系列- Spring Beans - 核心类的基本介绍

    Spring源码系列- Spring Beans - 核心类的基本介绍 读过上一篇文章的读者应该都能对Spring的体系结构有一个大致的了解,在结尾处,我也说过会从spring-beans包开始分析, ...

  5. 【spring源码系列-05】refresh中prepareRefresh方法的执行流程

    Spring源码系列整体栏目 内容 链接地址 [一]spring源码整体概述 https://blog.csdn.net/zhenghuishengq/article/details/13094088 ...

  6. spring源码系列一--BeanDefinition

    如果说java是由对象组成,那么spring-framework框架可以说是由BeanDefinition所构成.BeanDefinitiion其实是spring中的顶级接口,我们在阅读源码之前必须要 ...

  7. Spring源码系列-第1章-Spring源码纵览【持续更新中】

    文章目录 必读 第1章-Spring源码纵览 概述 简单的继承关系图 Spring框架整体流程 核心组件接口分析 Resource资源 方法 实现类 ResourceLoader资源加载器 方法 实现 ...

  8. Spring源码系列:BeanFactory的创建

    2019独角兽企业重金招聘Python工程师标准>>> Spring的Ioc容器其实就是一个bean的关系网,依赖于core,bean,context三个组件来构建的.在spring ...

  9. Spring源码系列(十三)——Spring源码编译及详细注解

    文章目录 1. 环境搭建 2. 代码编译 2.1 编译代码 2.1.1 build.gradle 2.1.1.1 第一处 2.1.1.2 第二处 2.1.2 gradle.properties 2.1 ...

最新文章

  1. 【AJAX】Ajax学习总结
  2. Hadoop学习笔记一 简要介绍
  3. JS动态加载脚本及对动态脚本内方法的调用
  4. 千家BBS系列-技术宝典(免费下载软件)
  5. usb接口供电不足_电脑USB接口不够用?来试试ORICO条纹hub扩展器吧
  6. 25个优秀的Ajax技术和实例
  7. Angular rxjs源代码分析:range(0, 10)的实现
  8. mysql row 日志格式_mysql row日志格式下 查看binlog sql语句
  9. Apache-tomcat-8.5.82下载安装以及环境变量配置
  10. leetcode 1175. Prime Arrangements(python)
  11. 城市引力模型——城市经济联系度制作
  12. 深度学习目标检测模型测试评价指标的选取及介绍
  13. 教育系统APP(三)
  14. [python] tornado supervisor监控 以及 Nginx反向代理
  15. 各大互联网公司面经分享:Java全栈知识+1500道大厂面试真题
  16. 电商总结-日志监控系统的解决方案
  17. 读书笔记16 《傅雷家书》 傅雷傅敏
  18. java获取dns记录_java-使用JNDI获取DNS SRV记录
  19. oracle 报表生成器的学习
  20. python内置函数open_Python内置函数(59)——open

热门文章

  1. Java中的Thread.sleep()– Java线程睡眠
  2. ROS的学习(十四)用C++写一个简单的接收者
  3. 开课吧:什么是排序算法
  4. Push or pull?
  5. 算法分析-动态规划-01背包
  6. ATEN瞄准专业级影音市场,发表全新VanCryst™视频系列产品线
  7. Java程序运行时间的计算
  8. Cobbler实现自动化安装操作系统
  9. 第三天 LINUX安全
  10. ASP.NET上传下载文件