3

前言

BeanDefinitionSpring中的十分重要的一个类,学习SpringbootSpring时,会经常遇到该类,所以本篇文章会对BeanDefinition的概念进行入门学习,同时一并学习定义注册,移除和查询BeanDefinitionBeanDefinitionRegistry接口。本篇文章用于帮助理解BeanDefinition的概念,同时作为笔者学习Springboot的笔记,有概念错误的地方敬请批评指正。

Springboot版本:2.4.1

正文

一. BeanDefinition简析

BeanDefinitionSpring中的重要接口,BeanDefinition的实现类用于描述Spring中的一个应该被实例化的bean的各种性质,包括bean的属性值,构造函数,方法等信息,除此之外,还额外描述beanSpring容器中的作用域,bean名称等信息。

可以将BeanDefinition类比于Java中的类的Class对象,在Java中可以使用一个类的Class对象来完成对象的实例化,但是在Spring中,单纯使用beanClass对象无法完成bean的实例化,因为Spring中的bean具备一些额外的性质,例如bean是否是单例,bean是否在容器中是懒加载,bean在容器中的名字,这些性质无法依靠类的Class对象来描述,所以Spring引入BeanDefinition来描述Spring中的一个应该被实例化的bean的各种性质。

Spring框架在启动时,会在ConfigurationClassPostProcessor这个bean工厂后置处理器中将需要被加载到容器中的bean扫描到并创建BeanDefinition,然后缓存到BeanFactorybeanDefinitionMap中,beanDefinitionMap是一个Map,用于存放BeanDefinition,键为bean在容器中的名称,值为bean对应的BeanDefinition

现在以Springboot启动为例,简要展示ConfigurationClassPostProcessor将需要被加载到容器中的bean扫描到并创建BeanDefinition然后放到beanDefinitionMap中的一个流程。在Springboot启动时,会先创建容器(也叫应用上下文),然后调用SpringApplicationrefreshContext()方法来初始化容器,在refreshContext()方法中会最终调用到容器的refresh()方法来完成初始化,这个调用链可以表示如下。

AbstractApplicationContextrefresh()方法中,会调用invokeBeanFactoryPostProcessors()方法来调用bean工厂后置处理器,ConfigurationClassPostProcessor就会在这里被调用,具体的ConfigurationClassPostProcessor的逻辑这里暂时不分析,现在将断点打到AbstractApplicationContext#refresh()方法中调用invokeBeanFactoryPostProcessors()方法的这一行代码,此时观察BeanFactory中的beanDefinitionMap如下所示。

事先已经定义好了一个bean,如下所示。

@Component
public class TestBean {

    public TestBean() {
        System.out.println("Initialize TestBean.");
    }

}

此时往后执行一步,再观察BeanFactory中的beanDefinitionMap如下所示。

可以看到BeanFactory中的beanDefinitionMap多了很多BeanDefinition,其中也包括事先定义好的TestBean,这是因为在ConfigurationClassPostProcessor中会将需要被加载到容器中的bean都扫描出来并创建成BeanDefinition,然后存放到beanDefinitionMap中,但是TestBean的构造函数中应该被打印的信息是没有被打印的,这说明ConfigurationClassPostProcessor中只会创建BeanDefinition并存放到beanDefinitionMap中,不会实际的实例化bean,真正的bean的实例化由AbstractApplicationContextfinishBeanFactoryInitialization()方法开启,这里暂不分析。

现在可知,Spring借助BeanDefinition来创建容器中的bean,容器中的每一个bean都会由一个BeanDefinition来描述,描述包括bean属性值,构造函数,方法,bean作用域,bean名称等信息,Spring在启动时会先扫描所有需要被加载到容器中的bean,然后为这些bean创建BeanDefinition并添加到BeanFactory中的beanDefinitionMap中。创建BeanDefinition时不会实例化beanbean的实例化在BeanDefinition创建之后。

二. BeanDefinitionRegistry简析

Springboot启动时,会创建容器,并根据WebApplicationType的不同,创建不同的容器,例如WebApplicationTypeSERVLET,此时使用的容器为AnnotationConfigServletWebServerApplicationContext,如果WebApplicationTypeNONE,此时使用的容器为AnnotationConfigApplicationContext,无论使用哪种容器,其内部持有一个BeanFactory容器,其实际类型为DefaultListableBeanFactoryDefaultListableBeanFactory是一个具有注册功能的容器,因为其实现了BeanDefinitionRegistry接口。

BeanDefinitionRegistry接口定义了对BeanDefinition的注册,移除和查询等操作,下面主要看一下DefaultListableBeanFactoryBeanDefinition的注册的实现,即registerBeanDefinition()方法,源码如下。

@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");

    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
        }
    }

    // 通过beanName将已经注册的BeanDefinition获取出来
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        // 如果已经使用当前beanName注册过BeanDefinition
        // 则判断是否允许以相同beanName注册不同的BeanDefinition以覆盖已存在的BeanDefinition
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            if (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 {
        // 检查bean实例是否已经开始创建
        if (hasBeanCreationStarted()) {
            synchronized (this.beanDefinitionMap) {
                // 将BeanDefinition缓存到beanDefinitionMap
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 将beanName缓存到beanDefinitionNames
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                // 从manualSingletonNames中将beanName移除,以防止beanName重复
                // manualSingletonNames中缓存了手动注册的单例的名称
                removeManualSingletonName(beanName);
            }
        }
        else {// 仍处于启动注册阶段
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
    else if (isConfigurationFrozen()) {
        clearByTypeCache();
    }
}

DefaultListableBeanFactory实现的registerBeanDefinition()方法中,会将beanNameBeanDefinition以键值对的形式缓存到beanDefinitionMap中,同时还会将beanName添加到beanDefinitionNames中。由于还会存在手动注册单例bean的情况,如果手动注册了单例bean,单例bean的名称会缓存在manualSingletonNames中,所以还需要在registerBeanDefinition()方法中保证beanDefinitionNamesmanualSingletonNames中的beanName不重复。

现在做一个小节,在Springboot启动时,创建的容器中会持有一个DefaultListableBeanFactory容器,其实现了BeanDefinitionRegistry接口,具备对BeanDefinition进行注册,删除和查询等功能,Springboot进行bean的扫描加载,自动装配时均会基于需要加载到容器中的bean创建BeanDefinition,并将创建好的BeanDefinition注册到DefaultListableBeanFactory容器中。

总结

BeanDefinition的主要作用是描述Spring中的bean,作用可以类比于Java中的Class对象,但是比Class对象能够描述更多的bean信息,例如bean作用域,是否懒加载等。在Springboot的启动阶段,每个需要被加载到容器中的bean会被创建为一个BeanDefinition,然后被注册到容器中,而Springboot中使用的容器均持有一个DefaultListableBeanFactory,其实现了BeanDefinitionRegistry接口,所以注册BeanDefinition到容器中,实际就是注册BeanDefinitionDefaultListableBeanFactory中,最终每个BeanDefinition会被缓存到DefaultListableBeanFactorybeanDefinitionMap中。

BeanDefinition只是一个接口,其有许多实现类,在本篇文章中并未进行分析,同时在BeanDefinition的创建过程中还有一个重要类ConfigurationClassPostProcessor,本篇文章也并未深入探究,上述的问题,将在后续的文章中逐一说明。
BeanDefinition只是一个接口,其有许多实现类,在本篇文章中并未进行分析,同时在BeanDefinition的创建过程中还有一个重要类ConfigurationClassPostProcessor,本篇文章也并未深入探究,上述的问题,将在后续的文章中逐一说明。


半夏之沫
65 声望31 粉丝