乐趣区

关于spring:SpringBeanDefinition简析

前言

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,本篇文章也并未深刻探索,上述的问题,将在后续的文章中逐个阐明。

退出移动版