共计 6229 个字符,预计需要花费 16 分钟才能阅读完成。
前言
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,如下所示。
@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 的实例化由 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()
办法,源码如下。
@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()
办法中,会将 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
,本篇文章也并未深刻探索,上述的问题,将在后续的文章中逐个阐明。