Spring(五)核心容器 - 注册 Bean、BeanDefinitionRegistry 简介

栏目: IT技术 · 发布时间: 4年前

内容简介:上篇文章我们对 BeanDefinition 进行了讨论,BeanDefinition 是对 Bean 的定义,其保存了 Bean 的各种信息,如属性、构造方法参数、是否单例、是否延迟加载等。这里的注册 Bean 是指将 Bean 定义成 BeanDefinition,之后放入 Spring 容器中,我们常说的容器其实就是 Beanfactory 中的一个 Map,key 是 Bean 的名称,value 是 Bean 对应的 BeanDefinition,这个注册 Bean 的方法由 BeanFactor

前言

上篇文章我们对 BeanDefinition 进行了讨论,BeanDefinition 是对 Bean 的定义,其保存了 Bean 的各种信息,如属性、构造方法参数、是否单例、是否延迟加载等。这里的注册 Bean 是指将 Bean 定义成 BeanDefinition,之后放入 Spring 容器中,我们常说的容器其实就是 Beanfactory 中的一个 Map,key 是 Bean 的名称,value 是 Bean 对应的 BeanDefinition,这个注册 Bean 的方法由 BeanFactory 子类实现。

注:本篇文章使用的 SpringBoot 版本为 2.0.3.RELEASE,其 Spring 版本为 5.0.7.RELEASE

正文

在前面的 《Spring(三)核心容器 - ApplicationContext 上下文启动准备》 文章中说过,当前环境的 BeanFactory 实现类是 DefaultListableBeanFactory,是一个具有注册功能的完整 Bean 工厂,注册 Bean 的方法是 registerBeanDefinition,DefaultListableBeanFactory 通过实现 BeanDefinitionRegistry 接口,重写该方法。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    ...

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
        ...
    }
    ...
}

讨论 registerBeanDefinition 方法之前,先来简单介绍 BeanDefinitionRegistry 接口。

1、BeanDefinitionRegistry 简介

BeanDefinitionRegistry 是一个接口,它定义了关于 BeanDefinition 的注册、移除、查询等一系列的操作。

public interface BeanDefinitionRegistry extends AliasRegistry {

    // 注册 BeanDefinition
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;

    // 移除 BeanDefinition
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    // 获取 BeanDefinition
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    // 根据 beanName 判断容器是否存在对应的 BeanDefinition 
    boolean containsBeanDefinition(String beanName);

    // 获取所有的 BeanDefinition
    String[] getBeanDefinitionNames();

    // 获取 BeanDefinition 数量
    int getBeanDefinitionCount();

    // 判断 beanName 是否被占用
    boolean isBeanNameInUse(String beanName);
}

该接口有三个实现类:DefaultListableBeanFactory、GenericApplicationContext、SimpleBeanDefinitionRegistry,其中 GenericApplicationContext 底层调用的是 DefaultListableBeanFactory 中的实现方法,所以严格意义上来说,只有两个实现类。这里,我们主要讨论 DefaultListableBeanFactory 中的方法实现。

2、registerBeanDefinition 方法注册 Bean

前面说过 registerBeanDefinition 方法的主要实现类是 DefaultListableBeanFactory :

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    ...
    
    // 存储所有的 BeanDefinition ,key 是 Bean 的名称。我们一直称呼的容器,底层就是这个 Map
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    // 存储所有 Bean 名称
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
    // 存储手动注册的单例 Bean 名称
    private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
    // 存储冻结的 BeanDefinition,留作后面缓存用
    private volatile String[] frozenBeanDefinitionNames;
    
    ...
    
    // 方法的入参为 Bean 名称和对应的 BeanDefinition
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        // 如果 beanDefinition 的实例为 AbstractBeanDefinition,则进行验证
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                // 验证:
                //     如果有重写方法,但是是工厂方法,则抛出异常,因为重写方法需要代理,而工厂方法无法代理;
                //     通过方法名称,判断 Bean 中该名称方法存在的数量,0:方法不存在,报错;1:方法非重载,overloaded 属性设为 false;
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition oldBeanDefinition;
        // 先从 beanDefinitionMap 中尝试获取 beanName 对应 BeanDefinition
        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        
        // 不为 null,则 beanName 对应的 BeanDefinition 已经存在
        if (oldBeanDefinition != null) {
            
            // 是否应允许覆盖 BeanDefinition,不允许则抛异常
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound.");
            }
            
            /***************************** 若允许覆盖 *****************************/
            
            // 判断 Bean 的角色大小:
            //      0:用户定义的 Bean、1:来源于配置文件的 Bean、2:Spring 内部的 Bean;
            // 当原 BeanDefinition 角色小于新的 BeanDefinition 角色时,输出一个 warn 日志,提示 BeanDefinition 被覆盖
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            }
            // 当新 BeanDefinition 属性值不等于原 BeanDefinition 属性值时,输出 info 提示信息
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 最后,输出 debug 日志信息:用等效的新 BeanDefinition 覆盖原 BeanDefinition
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 添加至 BeanDefinition 集合,并覆盖原 BeanDefinition
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        
        // Map 中无对应的 BeanDefinition,则直接注册
        else {
            // 已开始创建 Bean 
            if (hasBeanCreationStarted()) {
                synchronized (this.beanDefinitionMap) {
                    // 将 Bean 对应的 BeanDefinition 放入 beanDefinitionMap 中
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    
                    // 创建新的 beanNames 集合,并将已缓存的 beanName 和新的 beanName 加入该集合
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    
                    // 在手动注册 Bean 的集合中,如果存在同名的 beanName,则将集合中同名的 beanName 删除
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            // 仍处于启动注册阶段
            else {
                // 将当前 Bean 对应的 BeanDefinition 放入 beanDefinitionMap 中
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 将当前 beanName 放入 beanDefinitionNames
                this.beanDefinitionNames.add(beanName);
                // 删除手动注册 Bean 集合中同名的 beanName
                this.manualSingletonNames.remove(beanName);
            }
            
            // 将存储冻结 BeanDefinition 的 Map 置为 null
            this.frozenBeanDefinitionNames = null;
        }

        // 当前注册的 BeanDefinition 已在 beanDefinitionMap 中存在,或者其实例已在存储单例 Bean 的 Map 中存在
        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            
            // 重置 BeanDefinition,主要做一些清理工作
            resetBeanDefinition(beanName);
        }
    }
}

执行完 registerBeanDefinition 方法后,Bean 的名称和对应的 BeanDefinition 就被放入了容器中,后续获取 Bean 也是从这个容器中获取。

当然,DefaultListableBeanFactory 还实现了 BeanDefinitionRegistry 接口的其它方法,如对 BeanDefinition 进行移除、判断是否存在、获取数量等操作,其实都是围绕 beanDefinitionMap 这个 Map 进行的,这里就不详细介绍。

需要注意的是 registerBeanDefinition 方法会在后面频繁被调用,后续会逐一提到。

最后

这篇文章主要对注册 Bean 的核心方法进行讨论,但其中涉及到了单例 Bean 实例注册,这和当前文章的注册 Bean 不同,当前保存的是任意 Bean 的信息,而后者,保存的是单例 Bean 的对象,我们将在下篇文章详细讨论。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

游戏化思维

游戏化思维

[美] 凯文·韦巴赫(Kevin Werbach)、[美] 丹·亨特(Dan Hunter) / 周逵、王晓丹 / 浙江人民出版社 / 2014-4 / 36.90

[内容简介] ●本书由开设了全世界第一个游戏化课程的沃顿商学院副教授凯文·韦巴赫和丹·亨特所著,第一次全面系统地介绍游戏化的理论,阐述了如何将游戏的理念应用到商业实践中。 ●作者指出,在商业竞争日益激烈的今天,传统的激励方式渐渐失效,未来的管理将更多地建立在员工和消费者的内在动机和自我激励上。这些制作精良、设计巧妙的游戏建立在多年来对人类动机和人类心理的研究基础之上,可以最大限度地激发......一起来看看 《游戏化思维》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具