containsBean方法的作用就是判断IoC容器中是否包含指定名称的Bean。该方法由BeanFactory接口定义,由AbstractBeanFactory实现。

判断IoC容器中是否包含指定beanName是从三个维度去判断的:

一、当前IoC容器的一级缓存(singletonObjects)中是否包含指定beanName的实例;

二、当前IoC容器中是否包含指定beanName的BeanDefinition信息;

三、当前IoC容器如果存在父容器,那么父容器是否存在指定beanName的Bean或者BeanDefinition信息。

了解了判断逻辑后,接下来再分析该方法的执行逻辑就十分简单。在该实现中,首先调用tranforme-dBeanName方法来对传入的name进行处理,接下来便是调用containsSingleton方法来判断当前IoC容器中的一级缓存(singletonObjects)中是否包含指定beanName的实例,调用containsBeanDefinition方法来判断当前IoC容器中是否包含指定beanName的BeanDefinition信息。

如果当前IoC容器中包含指定name的Bean实例或者BeanDefinition,接下来会再做一次验证,判断指定name所对应的Bean类型(注意,这里讲的Bean类型,指的是更宽泛的概念,IoC容器中的Bean大体可以分为两种类型:一种是普通Bean,一种是FactoryBean)。

调用BeanFactoryUtils的isFactoryDereference方法来判断传入的name是否是一个FactoryBean的beanName,注意这里是对判断结果取反。如果该判断不成立,则意味着传入的name所对应的Bean必定是一个FactoryBean,调用isFactoryBean方法来进行验证。

以上是当前IoC容器中存在指定name的Bean实例或者BeanDefinition信息的场景,如果当前IoC容器不存在,那么则判断当前IoC容器其父容器是否不等于空,并调用父容器的containsBean方法,返回父容器的判断结果(这是一个递归查找,假设父容器也有父容器,层层查找)。

// AbstractBeanFactory#containsBean
@Override
public boolean containsBean(String name) {String beanName = transformedBeanName(name);if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));}// Not found -> check parent.BeanFactory parentBeanFactory = getParentBeanFactory();return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
}// DefaultSingletonBeanRegistry#containsSingleton
@Override
public boolean containsSingleton(String beanName) {return this.singletonObjects.containsKey(beanName);
}// DefaultListableBeanFactory#containsBeanDefinition
@Override
public boolean containsBeanDefinition(String beanName) {Assert.notNull(beanName, "Bean name must not be null");return this.beanDefinitionMap.containsKey(beanName);
}

BeanFactoryUtils的isFactoryDereference方法实现很简单,判断传入的name不等于空,并且name是以“&”开始。

String FACTORY_BEAN_PREFIX = "&";public static boolean isFactoryDereference(@Nullable String name) {return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}

isFactoryBean方法由ConfigurableBeanFactory接口定义,由AbstractBeanFactory类实现,在该实现中,首先调用transformedBeanName方法对传入的name进行处理,接下来调用getSingleton方法来获取IoC容器中的一级缓存或二级缓存中是否存在指定beanName的实例,如果存在,则判断是否是FactoryBean类型。

如果getSingleton方法返回值为空,则判断当前IoC容器是否不包含指定beanName的BeanDefinition信息并且当前IoC容器存在父容器并且父容器是ConfigurableBeanFactory类型。如果判断成立,则调用父容器的isFactoryBean方法并返回。

最后调用重载的isFactoryBean方法,首先获取beanName所对应的BeanDefinition,然后根据BeanD-efinition信息来判断指定beanName所对应的Bean是否是一个FactoryBean。

// AbstractBeanFactory#isFactoryBean
@Override
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {String beanName = transformedBeanName(name);Object beanInstance = getSingleton(beanName, false);if (beanInstance != null) {return (beanInstance instanceof FactoryBean);}// No singleton instance found -> check bean definition.if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {// No bean definition found in this factory -> delegate to parent.return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);}return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}

总结

IoC容器的containsBean方法拥有层次性判断能力,即当前容器→父容器→父容器的父容器…层层进行查找。

用该方法来判断IoC容器中是否包含某个Bean,即使返回值为true,但不代表指定beanName所关联的Bean已经被初始化,因为通过上面代码分析可以得知支撑其判断的数据来源部分是来自beanDefi-nitionMap。

另外通过registerSingleton方法注册的Bean也是支撑IoC容器用来判断的数据来源,因为通过该方法注册的Bean是直接被保存进singletonObjects中,即一级缓存。

如何判断IoC容器中是否存在指定Bean?相关推荐

  1. IOC 容器中那些鲜为人知的细节(关于 FactoryBean 和 BeanFactory)

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新) 在 Spring 中,有两个很容易混淆的类:BeanFactory 和 FactoryBean. BeanFa ...

  2. java 从一个容器获取对象,如何从 Spring IoC 容器中获取对象?

    前面几篇文章主要分析了 Spring IoC 容器如何初始化,以及解析和注册我们定义的 bean 信息. 其中,「Spring 中的 IoC 容器」对 Spring 中的容器做了一个概述,「Sprin ...

  3. IOC 容器中那些鲜为人知的细节(关于 延时加载)

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新)) 通过前面我们对 IOC 容器的实现和工作原理分析,我们已经知道 IOC 容器的初始化过程就是对 Bean定义 ...

  4. IOC容器中bean的生命周期,iocbean生命周期

    原文地址:http://www.bkjia.com/Javabc/1149957.html IOC容器中bean的生命周期,iocbean生命周期 一.Bean的生命周期 Spring IOC容器可以 ...

  5. IOC容器中bean的生命周期

    一.Bean的生命周期 Spring IOC容器可以管理Bean的生命周期,允许在Bean生命周期的特定点执行定制的任务. Spring IOC容器对Bean的生命周期进行管理的过程如下: (1).通 ...

  6. 头条一面:Spring IOC容器中只存放单例Bean吗?

    最近,很多小伙伴出去面试,感觉自己面的不是很理想,回来后,不少小伙伴把面试题做了记录发给我,让我给大家解析下,然后发出来.当我看到这些面试题时,快速在脑海中构建起了整个知识体系,从基础到框架.从分布式 ...

  7. PHP array_key_exists() 函数(判断某个数组中是否存在指定的 key)

    定义和用法 array_key_exists() 函数判断某个数组中是否存在指定的 key,如果该 key 存在,则返回 true,否则返回 false. 语法 array_key_exists(ke ...

  8. Spring5 - 向IOC容器中添加组件的4种方式

    文章目录 概述 方式一: @CompentScan 适用场景 Code 方式二: @Bean 适用场景 Code 方式三: @Import 适用场景 Code Demo1 Code Demo2 + 实 ...

  9. IOC 容器中那些鲜为人知的细节

    通过前面章节中对Spring IOC 容器的源码分析,我们已经基本上了解了Spring IOC 容器对Bean 定义资源的定位.载入和注册过程,同时也清楚了当用户通过getBean()方法向IOC 容 ...

  10. 六、spring之通过FactoryBean为ioc容器中添加组件

    前面我们已经介绍了几种为容器中添加组件的方法,今天一起学习通过FactoryBean添加组件的方法. 首先我们准备一个类,也就是我们需要注册进spring的ioc容器中的类 类Color: // 不必 ...

最新文章

  1. 为什么说混合云是新基建的流行架构?文末彩蛋!
  2. 计算机的主要硬件部件,主要内容: 计算机的基本概念 系统硬件组成(主要部件、系...的.ppt 文档全文预览...
  3. 属于链路状态路由选择协议,
  4. 图灵2008年12月出版的计算机图书
  5. css文本行高是哪个属性_CSS中的line-height行高属性的使用技巧小结
  6. 10月21日下午PHP常用函数
  7. Google I/O 2018 之后, Android 工程师将何去何从?
  8. Error:java: Compilation failed: internal java compiler error
  9. ios 动画 隐藏tabbar_iOS_自定义转场TabBar的隐藏动画
  10. 算法笔记:二叉树的序列化和反序列化(剑指 Offer 37)
  11. 框架整合——Spring与MyBatis框架整合
  12. 实验报告C语言顺序结构程序,顺序结构程序设计-C语言程序实验报告
  13. vscode 注释多行代码_如何在Visual Studio Code中注释多行?
  14. MODTRAN辐射传输模型使用笔记
  15. 论文阅读(边缘计算人工智能工业互联网)
  16. 关于在IE8浏览器的环境下页面一直刷新的问题
  17. Vue3.2——vue-seamless-scroll的使用
  18. 王道ch3-Stackp90_2.有一个列车,HS分别表示硬座软座,利用一个栈将序列调整为S在H之前
  19. 二进制压缩 - 算法
  20. 10分钟教你搭建一个可公网访问的私人网盘,和付费网盘彻底say goodbye~

热门文章

  1. 跑毒的乌龟-0 : 随机漫步
  2. C/C++[codeup 6112]Be Unique
  3. c语言山东科技大学答案oj,山东科技大学oj部分题目记答案.doc
  4. mysql手动编译安装_手动编译安装Mysql
  5. 基于深度学习的视觉 SLAM 综述
  6. 从单向链表中删除指定值的节点
  7. C语言不支持函数重载的原因
  8. Java反射----理解反射的源头Class类
  9. php时间戳防盗链,七牛云储存CDN时间戳防盗链PHP获取方法
  10. centos7查看当前系统时间、_CentOS 7修改系统时间及硬件时间