Spring源码系列:BeanDefinition载入(下)
在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载入(下)相关推荐
- Ioc容器beanDefinition-Spring 源码系列(1)
Ioc容器beanDefinition-Spring 源码系列(1) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器 ...
- Spring源码系列:依赖注入(二)createBean
在Spring源码系列:依赖注入(一)(AbstractBeanFactory-getBean)最后说道getBean是依赖注入的起点,bean的创建都是通过createBean来完成具体的创建的.c ...
- Spring源码系列(十二)Spring创建Bean的过程(二)
1.写在前面 上篇博客主要Spring在创建Bean的时候,第一次调用的Bean的后置处理器的过程,同时笔者也打算将整个Spring创建的Bean的过程,通过这个系列,将Bean的创建过程给讲清楚,废 ...
- Spring源码系列- Spring Beans - 核心类的基本介绍
Spring源码系列- Spring Beans - 核心类的基本介绍 读过上一篇文章的读者应该都能对Spring的体系结构有一个大致的了解,在结尾处,我也说过会从spring-beans包开始分析, ...
- 【spring源码系列-05】refresh中prepareRefresh方法的执行流程
Spring源码系列整体栏目 内容 链接地址 [一]spring源码整体概述 https://blog.csdn.net/zhenghuishengq/article/details/13094088 ...
- spring源码系列一--BeanDefinition
如果说java是由对象组成,那么spring-framework框架可以说是由BeanDefinition所构成.BeanDefinitiion其实是spring中的顶级接口,我们在阅读源码之前必须要 ...
- Spring源码系列-第1章-Spring源码纵览【持续更新中】
文章目录 必读 第1章-Spring源码纵览 概述 简单的继承关系图 Spring框架整体流程 核心组件接口分析 Resource资源 方法 实现类 ResourceLoader资源加载器 方法 实现 ...
- Spring源码系列:BeanFactory的创建
2019独角兽企业重金招聘Python工程师标准>>> Spring的Ioc容器其实就是一个bean的关系网,依赖于core,bean,context三个组件来构建的.在spring ...
- 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 ...
最新文章
- 【AJAX】Ajax学习总结
- Hadoop学习笔记一 简要介绍
- JS动态加载脚本及对动态脚本内方法的调用
- 千家BBS系列-技术宝典(免费下载软件)
- usb接口供电不足_电脑USB接口不够用?来试试ORICO条纹hub扩展器吧
- 25个优秀的Ajax技术和实例
- Angular rxjs源代码分析:range(0, 10)的实现
- mysql row 日志格式_mysql row日志格式下 查看binlog sql语句
- Apache-tomcat-8.5.82下载安装以及环境变量配置
- leetcode 1175. Prime Arrangements(python)
- 城市引力模型——城市经济联系度制作
- 深度学习目标检测模型测试评价指标的选取及介绍
- 教育系统APP(三)
- [python] tornado supervisor监控 以及 Nginx反向代理
- 各大互联网公司面经分享:Java全栈知识+1500道大厂面试真题
- 电商总结-日志监控系统的解决方案
- 读书笔记16 《傅雷家书》 傅雷傅敏
- java获取dns记录_java-使用JNDI获取DNS SRV记录
- oracle 报表生成器的学习
- python内置函数open_Python内置函数(59)——open