Spring (five) core container - Register Bean, BeanDefinitionRegistry Profile

Foreword

BeanDefinition last article we discussed, BeanDefinition is the definition of the Bean, Bean save a variety of information, such as attributes, constructor arguments, whether singleton, whether lazy loading and so on. Here is the registration Bean Bean is defined as BeanDefinition, after a drop in the Spring container, we often say that the container is actually Beanfactory in a Map, key is the name of the Bean, value is Bean corresponding BeanDefinition, this method of registration Bean implemented by a subclass of BeanFactory.

Note: SpringBoot version of this article used to 2.0.3.RELEASE, its Spring version 5.0.7.RELEASE

text

In front of the "Spring (c) of the core container - ApplicationContext context start preparing," the article said, the current environment BeanFactory implementation class is DefaultListableBeanFactory, is a full-Bean factory registration features by registering Bean is registerBeanDefinition, DefaultListableBeanFactory by implementing BeanDefinitionRegistry interface override this method.

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

    ...

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

Before discussing registerBeanDefinition method, first take a brief introduction BeanDefinitionRegistry interface.

1, BeanDefinitionRegistry Profile

BeanDefinitionRegistry is an interface that defines the registration on the BeanDefinition, remove, query and a series of operations.

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);
}

The interface has three implementation classes: DefaultListableBeanFactory, GenericApplicationContext, SimpleBeanDefinitionRegistry, which GenericApplicationContext low-level calls that implementation of DefaultListableBeanFactory, so strictly speaking, only two implementation classes. Here, we focus on DefaultListableBeanFactory method of implementation.

2, registerBeanDefinition method to register Bean

I said before the main method of implementation class registerBeanDefinition is 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);
        }
    }
}

After performing registerBeanDefinition method, and the corresponding name Bean BeanDefinition was placed in the container, it is obtained from subsequent retrieval Bean this container.

Of course, DefaultListableBeanFactory also implements other methods BeanDefinitionRegistry interfaces, such as BeanDefinition were removed to determine whether there is, get the number of other operations, they are actually beanDefinitionMap this Map carried around, here is not described in detail.

Note that the method will often be called registerBeanDefinition later, will be referred to the subsequent one by one.

At last

This article focuses on the core method of registering Bean discuss, but which involves a singleton Bean instance registration, various registration Bean This current article, currently stored is arbitrary Bean of information, and the latter saved is a singleton Bean object, we will discuss in the next article in detail.

Guess you like

Origin www.cnblogs.com/loongk/p/12297193.html