前言BeanDefinition是Spring中一个非常重要的类。在学习Springboot和Spring的时候,经常会遇到这个类,所以本文将介绍BeanDefinition的概念,一起学习。定义BeanDefinitionRegistry接口,用于注册、移除和查询BeanDefinition。本文用于帮助理解BeanDefinition的概念,同时作为作者学习Springboot的笔记,如有概念错误请批评指正。Springbootversion:2.4.1正文一、BeanDefinition简析BeanDefinition是Spring中的一个重要接口。BeanDefinition的实现类用于描述一个bean在Spring中应该被实例化的各种属性,包括bean的属性值和构造函数。、方法等信息,此外还额外描述了bean在Spring容器中的作用域、bean名称等信息。BeanDefinition可以类比为Java中类的Class对象。在Java中,可以使用类的Class对象来完成对象的实例化,但是在Spring中,并不能简单地使用bean的Class对象来完成bean的实例化,因为Spring中的bean有一些附加的属性,比如bean是否是单例,bean在容器中是否懒加载,bean在容器中的名称。这些属性不能用类的Class对象来描述,所以Spring引入了BeanDefinition来描述Spring应该实例化的bean的各种属性之一。Spring框架启动时,会在bean工厂后处理器ConfigurationClassPostProcessor中扫描需要加载到容器中的bean,并创建一个BeanDefinition,然后缓存在BeanFactory的beanDefinitionMap中。beanDefinitionMap是一个用来存储BeanDefinition的Map。key是容器中bean的名称,value是bean对应的BeanDefinition。下面以Springboot启动为例,简单展示一个流程,ConfigurationClassPostProcessor扫描需要加载到容器中的bean,创建一个BeanDefinition,然后放到beanDefinitionMap中。Springboot启动时,会先创建容器(也叫应用上下文),然后调用SpringApplication的refreshContext()方法初始化容器。在refreshContext()方法中,最终会调用容器的refresh()方法完成初始化。这个调用链可以表示如下。在AbstractApplicationContext的refresh()方法中,会调用invokeBeanFactoryPostProcessors()方法调用bean工厂后处理器,这里会调用ConfigurationClassPostProcessor。ConfigurationClassPostProcessor的具体逻辑这里暂且不分析,现在断点在AbstractApplicationContext#refresh()方法中调用invokeBeanFactoryPostProcessors()方法的代码行,此时,观察beanDefinitionMap在BeanFactory中如下。预先定义了一个bean,如下图。@ComponentpublicclassTestBean{publicTestBean(){System.out.println("初始化TestBean。");}}此时往回执行一步,然后观察BeanFactory中的beanDefinitionMap如下图。可以看到BeanFactory中的beanDefinitionMap中多了很多BeanDefinitions,包括预定义的TestBean。这是因为在ConfigurationClassPostProcessor中,所有需要加载到容器中的bean都会被扫描并创建到BeanDefinition中,然后存储到beanDefinitionMap中,但是TestBean的构造函数中应该打印的信息并没有打印出来,也就是说ConfigurationClassPostProcessor中只会创建BeanDefinition,并存储在beanDefinitionMap中,并不会真正实例化bean。真正的bean是通过实例化的finishBeanFactoryInitialization的AbstractApplicationContext()方法启用的,这里不再分析。现在可以看出Spring是使用BeanDefinition在容器中创建bean的。容器中的每个bean都将由一个BeanDefinition来描述。描述包括bean属性值、构造函数、方法、bean作用域和bean名称等信息。当Spring启动时,会先扫描所有需要加载到容器中的bean,然后为这些bean创建BeanDefinitions,并添加到BeanFactory中的beanDefinitionMap中。创建BeanDefinition时不实例化bean,创建BeanDefinition后才实例化bean。2、BeanDefinitionRegistry简析Springboot启动时会创建一个容器,根据WebApplicationType创建不同的容器。例如WebApplicationType为SERVLET,此时使用的容器为AnnotationConfigServletWebServerApplicationContext。如果WebApplicationType为NONE,此时使用的容器为AnnotationConfigApplicationContext。无论使用哪个容器,其内部都持有一个BeanFactory容器,其实际类型为DefaultListableBeanFactory。DefaultListableBeanFactory是一个带有注册功能的容器,因为它实现了BeanDefinitionRegistry接口。BeanDefinitionRegistry接口定义了BeanDefinition的注册、移除、查询等操作。下面主要看DefaultListableBeanFactory注册BeanDefinition的实现,即registerBeanDefinition()方法。源代码如下。@OverridepublicvoidregisterBeanDefinition(StringbeanName,BeanDefinitionbeanDefinition)throwsBeanDefinitionStoreException{Assert.hasText(beanName,"Bean名称不能为空");Assert.notNull(beanDefinition,"BeanDefinition不能为空");if(beanDefinitioninstanceofAbstractBean){try{((AbstractBeanDefinition)beanDefinition).validate();}catch(BeanDefinitionValidationExceptionex){thrownewBeanDefinitionStoreException(beanDefinition.getResourceDescription(),beanName,“bean定义验证失败”,ex);}}//通过beanName获取注册的BeanDefinitionBeanDefinitionexistingDefinition=this.beanDefinitionMap.get(beanName);if(existingDefinition!=null){//如果BeanDefinition已经用当前的beanName注册过//判断是否允许注册不同的beanName同一个beanNameBeanDefinition覆盖已有的BeanDefinitionif(!isAllowBeanDefinitionOverriding()){thrownewBeanDefinitionOverrideException(beanName,beanDefinition,existingDefinition);}elseif(existingDefinition.getRole()
