文章目录

  • 前言
  • 一、管理的必要性
    • 框架设计
    • 工程实现
  • 二、Spring的实现
    • 1.抽象接口BeanDefinitionRegistry
    • 2. 具体实现DefaultListableBeanFactory
  • 三、特色方法
    • removeBeanDefinition
    • BeanDefinitionOverriding
  • 总结

前言

前面几篇文章中,我们梳理了BeanDefinition相关的Resource、Resource加载、基于XML文件的BeanDefinition不同颗粒度解析,和XML中自定义标签解析。接下来,看看BeanDefinition的注册。

在开始之前,先回顾下BeanDefinition。BeanDefinition是Bean的相关定义。对一个具体的BeanDefinition,对内包含BeanDefinition对应的class,scope,init-method,destory-method等等,对外包含对其他BeanDefinition的关联关系,包括依赖和继承。
到这里,咱们讨论的是单个BeanDefinition。实际工程中,Bean有多个,对应的BeanDefinition也不止一个。于是灵魂拷问来了,要不要管理,如何管理?

所以,本文先YY下BeanDefinition管理的必要性,再看BeanFactory是怎么管理的,最后仔细看下Spring作者在操刀时加入的个人思想。


一、管理的必要性

框架设计

BeanDefinition对象是一类关键对象。主要体现在依赖关系复杂。依赖关系包括非BeanDefinition对BeanDefinition的依赖,以及BeanDefinition之间的依赖,就像中年人上有老,下有小同时还得照顾亲戚。依赖关系复杂,直接体现就是对象构造过程比较曲折,简单说不能 new XXBeanDefinition() 就完事了。

工程实现

由于存在依赖,也需要快速寻找依赖,很自然就想到通过集合集中管理,比如使用Map集合。Spring中也确实是这么干的。于是就需要一个Map集合+写入/获取方法。于是就YY出来了一个BeanDefinitionFactory(实际上是不存在的)接口,提供一个写入和获取方法。具体实现类内部通过Map集合实现读写。

二、Spring的实现

1.抽象接口BeanDefinitionRegistry

Spring首先定义了BeanDefinitionRegistry,提供了读写的方法。这个基本上和我们的想法是

代码如下:

public interface BeanDefinitionRegistry extends AliasRegistry {/*** Register a new bean definition with this registry.* Must support RootBeanDefinition and ChildBeanDefinition.* @param beanName the name of the bean instance to register* @param beanDefinition definition of the bean instance to register* @throws BeanDefinitionStoreException if the BeanDefinition is invalid* @throws BeanDefinitionOverrideException if there is already a BeanDefinition* for the specified bean name and we are not allowed to override it* @see GenericBeanDefinition* @see RootBeanDefinition* @see ChildBeanDefinition*/void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;/*** Remove the BeanDefinition for the given name.* @param beanName the name of the bean instance to register* @throws NoSuchBeanDefinitionException if there is no such bean definition*/void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;/*** Return the BeanDefinition for the given bean name.* @param beanName name of the bean to find a definition for* @return the BeanDefinition for the given name (never {@code null})* @throws NoSuchBeanDefinitionException if there is no such bean definition*/BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;/*** Check if this registry contains a bean definition with the given name.* @param beanName the name of the bean to look for* @return if this registry contains a bean definition with the given name*/boolean containsBeanDefinition(String beanName);/*** Return the names of all beans defined in this registry.* @return the names of all beans defined in this registry,* or an empty array if none defined*/String[] getBeanDefinitionNames();/*** Return the number of beans defined in the registry.* @return the number of beans defined in the registry*/int getBeanDefinitionCount();/*** Determine whether the given bean name is already in use within this registry,* i.e. whether there is a local bean or alias registered under this name.* @param beanName the name to check* @return whether the given bean name is already in use*/boolean isBeanNameInUse(String beanName);}

2. 具体实现DefaultListableBeanFactory

代码如下(示例):

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {// 省略BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);// 省略
}

到这里,基本上和前面的预期差不多,但是如果仔细看源码,其中的复杂程度远超想象。本文中,我们先关注BeanDefinition注册过程,忽略其他代码。


三、特色方法

removeBeanDefinition

既然都集合管理了,那么增删改查这套应该给整齐了。但具体什么时候会使用删除,后面的文章中我们再讨论。Spring中许多代码在写的时候,方法都是完整的,哪怕暂时用不到可以先留空。至少从逻辑上看,相关操作都是完整的。

BeanDefinitionOverriding

终点关注这个overriding,就意味着可以覆盖。既然可以覆盖总得有一些条件吧。咱们仔细看下源码。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {// 省略校验代码 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);if (existingDefinition != null) {// 是否允许覆盖if (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);}// 角色比较else if (existingDefinition.getRole() < beanDefinition.getRole()) {// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTUREif (logger.isInfoEnabled()) {logger.info("Overriding user-defined bean definition for bean '" + beanName +"' with a framework-generated bean definition: replacing [" +existingDefinition + "] with [" + beanDefinition + "]");}}// 已存比较else if (!beanDefinition.equals(existingDefinition)) {if (logger.isDebugEnabled()) {logger.debug("Overriding bean definition for bean '" + beanName +"' with a different definition: replacing [" + existingDefinition +"] with [" + beanDefinition + "]");}}else {if (logger.isTraceEnabled()) {logger.trace("Overriding bean definition for bean '" + beanName +"' with an equivalent definition: replacing [" + existingDefinition +"] with [" + beanDefinition + "]");}}this.beanDefinitionMap.put(beanName, beanDefinition);}else {// 容器已启动的特殊处理暂时忽略}}

从代码中可以看到:

  1. 对于重名的BeanDefinition,如果不允许overriding直接异常;
  2. 如果允许overriding,先比较角色。这个角色在Spring中定义了3种,级别从低到高分别是ROLE_APPLICATION(用户定义Bean), ROLE_SUPPORT(Spring内部使用,可能跟用户有关), ROLE_INFRASTRUCTURE(Spring内部使用,和框架使用者完全无关)。越大优先级越高。高优先级可以覆盖低优先级的BeanDefinition。
  3. 如果允许overriding, 并且两个BeanDefinition不相等直接覆盖;
  4. 关于容器已启动时的特殊处理,后续文章再做讨论。

总结

以上就是今天要讲的内容,本文梳理了Spring中BeanDefinition的注册思路和实现过程。如果对你有所帮助,请让我知道,感谢你的阅读。

第四篇 再读Spring 之BeanDefinition注册相关推荐

  1. 第二篇 再读Spring 之 BeanDefinition解析

    第二篇 再读Spring 之 BeanDefinition解析 文章目录 第二篇 再读Spring 之 BeanDefinition解析 一.颗粒度问题 二.细说Spring中不同颗粒度对象在解析中的 ...

  2. Spring中将BeanDefinition注册到IOC容器中

    Spring中将BeanDefinition注册到IOC容器中 XML配置元信息 <bean name="-" - /> 注解: @Bean,@Component,@I ...

  3. 第四篇:读《穷查理宝典》

    本书适合谁读? 查理芒格和巴菲特联手创造了有史以来最优秀的投资纪录,目前个人财富17亿美元.如果你想知道查理芒格是怎么取得这么出色的成就的,想听他总结自己的人生心得,或者你对投资有兴趣,建议阅读本书. ...

  4. JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快!

    JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快! 一.ReentrantReadWriteLock(读写锁) 1.读写锁存在 ...

  5. 十年后2023年再读这篇文章,看看我将会怎么样?

    看到一篇文章不错[清华差生10年奋斗经历] ,写给将要工作的自己,十年后2023年再读这篇文章,看看我将会怎么样? 在2012年收关时刻,看到如此激励的文章,实在是我的幸运.文章讲述了所谓清华差生的奋 ...

  6. 十年后2023年再读这篇文章,看看我将会怎么样

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 看到一篇 ...

  7. spring之旅第四篇-注解配置详解

    spring之旅第四篇-注解配置详解 一.引言 最近因为找工作,导致很长时间没有更新,找工作的时候你会明白浪费的时间后面都是要还的,现在的每一点努力,将来也会给你回报的,但行好事,莫问前程!努力总不会 ...

  8. 想读Spring源码?先从这篇「 极简教程」开始

    来自:Java中文社群 为什么要阅读源码?这是一个有趣的问题,类似的问题还有,为什么要看书?为什么要爬山? 这也是一个哲学问题,我想每个人都有不同的答案,下面我是对阅读源码好处的一些思考.(PS:也欢 ...

  9. 想读Spring源码?先从这篇「 极简教程」开始吧...

    为什么要阅读源码?这是一个有趣的问题,类似的问题还有,为什么要看书?为什么要爬山? 这也是一个哲学问题,我想每个人都有不同的答案,下面我是对阅读源码好处的一些思考. (PS:也欢迎你在评论区留言补充) ...

最新文章

  1. 2022-2028年中国超高清视频产业投资分析及前景预测报告
  2. 快速理解编码,unicode与utf-8
  3. 云炬WEB开发教程2-2 node.js和npm介绍和安装
  4. 便携式三星mysql_JDBC链接mysql - 三星蓝
  5. 数据模型和数据库系统的模型结构
  6. 具体数学:计算机科学基础:第2版
  7. Java学习日报—Swagger介绍 与 布隆过滤器详解—2021/12/01
  8. Java中实现对象的比较
  9. Linux学习之十一、环境变量的功能
  10. MMKV_MMKV - 由微信开发的高效,小巧的移动端key-value存储框架,适用于iOS和Android...
  11. Java 输入输出流实验
  12. 数据结构c语言课程设计报告,数据结构c语言课程设计报告.doc
  13. [CAN BUS] USB-CAN adpter / USB转CAN 开源项目推荐(CANable candlelight cangaroo)
  14. [数据压缩作业2]TIFF文件格式分析
  15. 如何压缩word文档的大小?
  16. [EdgeAI] NXP eIQ 机器学习Toolkit (二):模型篇
  17. 简单正则^(?![^a-zA-Z]+$)(?!\D+$)[0-9a-zA-Z]{6,35}$
  18. Python 树状图怎么画
  19. 秒 毫秒 微秒 纳秒 皮秒。。。时间单位换算
  20. 黑苹果Big Sur触摸屏驱动教程

热门文章

  1. 孩子stem教育特殊之处
  2. JS --引用数据类型
  3. 教育平台项目后台管理系统:视频讲解
  4. Postgresql源码(5)缓冲区管理
  5. sublime 3 build 3126 code ,压缩包在我的360企业云盘里,搜sublime
  6. android客户端与服务器端交互 如何保持session
  7. mac连接手机 vm_苹果 Mac 上的虚拟机怎么联接 iPhone
  8. 付宇泽20190919-4 单元测试,结对
  9. python安装盒怎么打开_python盒图
  10. Spring框架02(IOC和DI)