前言
BeanDefinition
是Spring中的非常重要的一个类,学习Springboot和Spring时,会常常遇到该类,所以本篇文章会对BeanDefinition
的概念进行入门学习,同时一并学习定义注册,移除和查问BeanDefinition
的BeanDefinitionRegistry
接口。本篇文章用于帮忙了解BeanDefinition
的概念,同时作为笔者学习Springboot的笔记,有概念谬误的中央敬请批评指正。
Springboot版本:2.4.1
注释
一. BeanDefinition简析
BeanDefinition
是Spring中的重要接口,BeanDefinition
的实现类用于形容Spring中的一个应该被实例化的bean的各种性质,包含bean的属性值,构造函数,办法等信息,除此之外,还额定形容bean在Spring容器中的作用域,bean名称等信息。
能够将BeanDefinition
类比于Java
中的类的Class
对象,在Java
中能够应用一个类的Class
对象来实现对象的实例化,然而在Spring中,单纯应用bean的Class
对象无奈实现bean的实例化,因为Spring中的bean具备一些额定的性质,例如bean是否是单例,bean是否在容器中是懒加载,bean在容器中的名字,这些性质无奈依附类的Class
对象来形容,所以Spring引入BeanDefinition
来形容Spring中的一个应该被实例化的bean的各种性质。
Spring框架在启动时,会在ConfigurationClassPostProcessor
这个bean工厂后置处理器中将须要被加载到容器中的bean扫描到并创立BeanDefinition
,而后缓存到BeanFactory
的beanDefinitionMap中,beanDefinitionMap是一个Map
,用于寄存BeanDefinition
,键为bean在容器中的名称,值为bean对应的BeanDefinition
。
当初以Springboot启动为例,简要展现ConfigurationClassPostProcessor
将须要被加载到容器中的bean扫描到并创立BeanDefinition
而后放到beanDefinitionMap中的一个流程。在Springboot启动时,会先创立容器(也叫利用上下文),而后调用SpringApplication
的refreshContext()
办法来初始化容器,在refreshContext()
办法中会最终调用到容器的refresh()
办法来实现初始化,这个调用链能够示意如下。
在AbstractApplicationContext
的refresh()
办法中,会调用invokeBeanFactoryPostProcessors()
办法来调用bean工厂后置处理器,ConfigurationClassPostProcessor
就会在这里被调用,具体的ConfigurationClassPostProcessor
的逻辑这里临时不剖析,当初将断点打到AbstractApplicationContext#refresh()
办法中调用invokeBeanFactoryPostProcessors()
办法的这一行代码,此时察看BeanFactory
中的beanDefinitionMap如下所示。
当时曾经定义好了一个bean,如下所示。
@Componentpublic 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的实例化由AbstractApplicationContext
的finishBeanFactoryInitialization()
办法开启,这里暂不剖析。
当初可知,Spring借助BeanDefinition
来创立容器中的bean,容器中的每一个bean都会由一个BeanDefinition
来形容,形容包含bean属性值,构造函数,办法,bean作用域,bean名称等信息,Spring在启动时会先扫描所有须要被加载到容器中的bean,而后为这些bean创立BeanDefinition
并增加到BeanFactory
中的beanDefinitionMap中。创立BeanDefinition
时不会实例化bean,bean的实例化在BeanDefinition
创立之后。
二. BeanDefinitionRegistry简析
Springboot启动时,会创立容器,并依据WebApplicationType
的不同,创立不同的容器,例如WebApplicationType
为SERVLET,此时应用的容器为AnnotationConfigServletWebServerApplicationContext
,如果WebApplicationType
为NONE,此时应用的容器为AnnotationConfigApplicationContext
,无论应用哪种容器,其外部持有一个BeanFactory
容器,其理论类型为DefaultListableBeanFactory
,DefaultListableBeanFactory
是一个具备注册性能的容器,因为其实现了BeanDefinitionRegistry
接口。
BeanDefinitionRegistry
接口定义了对BeanDefinition
的注册,移除和查问等操作,上面次要看一下DefaultListableBeanFactory
对BeanDefinition
的注册的实现,即registerBeanDefinition()
办法,源码如下。
@Overridepublic 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()
办法中,会将beanName和BeanDefinition
以键值对的模式缓存到beanDefinitionMap中,同时还会将beanName增加到beanDefinitionNames中。因为还会存在手动注册单例bean的状况,如果手动注册了单例bean,单例bean的名称会缓存在manualSingletonNames中,所以还须要在registerBeanDefinition()
办法中保障beanDefinitionNames和manualSingletonNames中的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
到容器中,理论就是注册BeanDefinition
到DefaultListableBeanFactory
中,最终每个BeanDefinition
会被缓存到DefaultListableBeanFactory
的beanDefinitionMap中。
BeanDefinition
只是一个接口,其有许多实现类,在本篇文章中并为进行剖析,同时在BeanDefinition
的创立过程中还有一个重要类ConfigurationClassPostProcessor
,本篇文章也并未深刻探索,上述的问题,将在后续的文章中逐个阐明。