BeanDefinition的合并
什么是合并?为什么需要合并。
在上篇文章中,我们学习了BeanDefinition的一些属性,其中有以下几个属性:
/**
* Return whether this bean is "abstract", that is, not meant to be instantiated.
* 跟合并的beanDefinition相关,如果是abstract,说明会被作为一个父BeanDefinition,不提供class属性
*/
boolean isAbstract();
String getParentName();//获取父类BeanDefinition,主要用于合并
这几个属性都和合并相关,那什么是合并呢?
我们先看以下官网对这方面的介绍
A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information, such as the initialization method, a static factory method name, and so on. A child bean definition inherits configuration data from a parent definition. The child definition can override some values or add others as needed. Using parent and child bean definitions can save a lot of typing. Effectively, this is a form of templating.
翻译如下:
bean定义可以包含很多配置信息,包括构造函数参数、属性值和特定于容器的信息,比如初始化方法、静态工厂方法名称,等等。子bean定义从父bean定义继承配置数据。子定义可以覆盖一些值或根据需要添加其他值。使用父bean和子bean定义可以节省大量的输入工作。实际上,这是模板的一种形式
我们按照官网给的一个例子来测试下,看到底发生了什么?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"
default-autowire="byType">
<!-- <bean id="auto" class="com.phr.service.AutoService" autowire="byType" autowire-candidate="false"/>-->
<!-- <bean id="yxService" class="com.phr.service.YxService"/>-->
<!-- <bean id="indexService" class="com.phr.service.IndexService"/>-->
<bean id="parent" abstract="true"
class="com.phr.official.merge.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="child"
class="com.phr.official.merge.DerivedTestBean"
parent="parent">
<property name="name" value="override"/>
</bean>
</beans>
public class DerivedTestBean {
private String name;
private String age;
//省略了get和set方法
}
public class TestBean {
private String name;
private String age;
//省略了get和set方法
}
public class Main06 {
public static void main(String[] args) {
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("spring.xml");
DerivedTestBean derivedTestBean = (DerivedTestBean) cc.getBean("child");
System.out.println("derivedTestBean的name = " + derivedTestBean.getName());
System.out.println("derivedTestBean的age = " + derivedTestBean.getAge());
}
}
输出结果为:
derivedTestBean的name = override
derivedTestBean的age = 1
在上面的例子中,我们将TestBean设置为父bean,并将name设置为parent,age设置为1.我们并没有直接设置子bean DerivedTestBean的age属性,从输出结果
我们看子bean DerivedTestBean的age属性里面有值了,而且属性值没有被父bean覆盖,也就是说子bean中已经存在的属性不会被父bean的属性覆盖。
合并的总结:
子bean会从父bean中继承没有的属性。
这个过程中,子bean存在的属性不会被父bean的属性覆盖。
关于合并需要注意的点:
子beandefinition中的class属性如果为null,同时父beanDefinition又指定了class属性,那么子beandefinition会继承这个class属性
子BeanDefinition
必须要兼容父BeanDefinition
中的所有属性。这是什么意思呢?以我们上面的demo为例,我们在父BeanDefinition
中指定了name跟age属性,但是如果子BeanDefinition
中子提供了一个name的setter方法,这个时候Spring在启动的时候会报错。因为子BeanDefinition
不能承接所有来自父BeanDefinition
的属性。
关于BeanDefinition
中abstract
属性的说明:
1、并不是作为父BeanDefinition
就一定要设置abstract
属性为true,abstract
只代表了这个BeanDefinition
是否要被Spring进行实例化并被创建对应的Bean,如果为true,代表容器不需要去对其进行实例化。
2、如果一个BeanDefinition
被当作父BeanDefinition
使用,并且没有指定其class
属性。那么必须要设置其abstract
为true
3、abstract=true
一般会跟父BeanDefinition
一起使用,因为当我们设置某个BeanDefinition
的abstract=true
时,一般都是要将其当作BeanDefinition
的模板使用,否则这个BeanDefinition
也没有意义,除非我们使用其它BeanDefinition
来继承它的属性
spring在哪些阶段做了合并?
1、扫描并获取到BeanDefinition
这个阶段的操作主要发生在invokeBeanFactoryPostProcessors,对应的方法调用栈如下:
对应执行该方法的类为:PostProcessorRegistrationDelegate
方法源码如下:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 这个beanFactoryPostProcessors集合一般情况下都是空的,除非我们手动调用容器的addBeanFactoryPostProcessor方法
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
// BeanDefinitionRegistryPostProcessor是一个特殊的BeanFactoryPostProcessor,需要先执行postProcessBeanDefinitionRegistry方法
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// 保存当前需要执行的实现了BeanDefinitionRegistryPostProcessor接口的后置处理器
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//发生一次beanDefinition的合并
// 首先,先执行实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 判断这个类是否还实现了PriorityOrdered接口
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 这里调用了getBean,所以生成一个BeanDefinitionRegistryPostProcessor的bean对象
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
//又发生一次beanDefinition的合并
// 首先,先执行实现了Ordered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后,最后其他普通的BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法
boolean reiterate = true;
// 在一个BeanDefinitionRegistryPostProcessor中可以注册另一个BeanDefinitionRegistryPostProcessor,所以需要递归找出所有的BeanDefinitionRegistryPostProcessor
// 一个没有实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor如果在内部注册了一个实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor,那么就是没有实现PriorityOrdered接口的先执行
while (reiterate) {
reiterate = false;
// 这里会再一次拿到实现了PriorityOrdered接口或Ordered接口的BeanDefinitionRegistryPostProcessor,所以需要processedBeans进行过滤
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
//再一次beanDefinition的合并
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// =======BeanDefinition 解析配置类(扫描,- @Bean, @Import),手动,接口, @Import
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
// 执行完BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法后,
// 再执行BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// 执行手动添加的非BeanDefinitionRegistryPostProcessor类型的Bean工厂后置处理器的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// 如果beanFactory没有可以注册BeanDefinition的功能,则没有BeanDefinitionRegistryPostProcessor,则执行Bean工厂后置处理器的postProcessBeanFactory方法
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 总结一下上面的流程:
// 1. 如果beanFactory实现了BeanDefinitionRegistry接口,则表示可以通过BeanDefinitionRegistryPostProcessor接口来注册BeanDefinition
// 2. 因为现在是Spring启动过程中的比较早的阶段(还没有开始扫描@Component),所以只能获取Spring默认添加到BeanFactory中的bean工厂后置处理器,以及程序员手动添加的bean工厂后置处理器
// 3. 执行的顺序是,先执行BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry方法,因为这个方法可以注册BeanDefinition
// 4. 先执行手动添加进行来的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,这个过程中可能会向BeanFactory中注册其他的BeanDefinitionRegistryPostProcessor
// 5. 从BeanFactory中获取PriorityOrdered接口的BeanDefinitionRegistryPostProcessor,并执行postProcessBeanDefinitionRegistry方法
// 6. 从BeanFactory中获取Ordered接口的BeanDefinitionRegistryPostProcessor,并执行postProcessBeanDefinitionRegistry方法
// 7. 在5,6步中都有可能注册新的BeanDefinitionRegistryPostProcessor的
// 8. 从BeanFactory中获取普通的BeanDefinitionRegistryPostProcessor,并执行postProcessBeanDefinitionRegistry方法
// 9. 在8步中也有可能注册新的BeanDefinitionRegistryPostProcessor,所以第8步会递归,直到没有新的BeanDefinitionRegistryPostProcessor注册进来了
// 10. 在前面的步骤中都是执行BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry方法,进行BeanDefinition的注册
// 11. BeanDefinition注册完了之后,因为BeanDefinitionRegistryPostProcessor本身也是一个BeanFactoryProcessor,所以最后再执行postProcessBeanFactory方法
// 12. 总结一句话就是:先通过BeanDefinitionRegistryPostProcessor注册BeanDefinition,再执行BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
// 在默认情况下,上面的步骤中只有一个BeanDefinitionRegistryPostProcessor会执行,就是ConfigurationClassPostProcessor,因为它是Spring默认在添加进去的
// BeanDefinitionRegistryPostProcessor是特殊的BeanFactoryPostProcessor,在上面的逻辑中都处理完了
// 所以接下来就是处理普通的BeanFactoryPostProcessor
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 默认情况下会拿到两个,一个就是ConfigurationClassPostProcessor,一个就是EventListenerMethodProcessor
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
// 保存直接实现了BeanFactoryPostProcessor接口和PriorityOrdered接口的后置处理器
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 保存直接实现了BeanFactoryPostProcessor接口和Ordered接口的后置处理器
List<String> orderedPostProcessorNames = new ArrayList<>();
// 保存直接实现了BeanFactoryPostProcessor接口的后置处理器,不包括那些实现了排序接口的类
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
// 把所有BeanFactoryPostProcessor进行分类
for (String ppName : postProcessorNames) {
// 拿到的BeanFactoryPostProcessor包括了BeanDefinitionRegistryPostProcessor,所以要跳过
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
// 先执行实现了PriorityOrdered接口的BeanFactoryPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
// 再执行实现了Ordered接口的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
// 最后执行普通的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// 到此,所有的BeanFactoryPostProcessor都执行完了
// 对于BeanFactoryPostProcessor我们可以这么理解:它是去完善BeanFactory的,比如向BeanFactory中去注册BeanDefinition
// 就好比:BeanFactory是一张白纸,每个BeanFactoryPostProcessor都去这张白纸上去画上一笔,这个白纸就丰满了
// 所以这段代码,虽然内容很多,但是在默认情况下,主要就是执行了ConfigurationClassPostProcessor
// 1. 先执行了ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法,基本上就是去注册BeanDefinition
// 2. 然后执行了ConfigurationClassPostProcessor的postProcessBeanFactory方法
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
每次调用beanFactory.getBeanNamesForType
都进行了一次bd
的合并。getBeanNamesForType
这个方法主要目的是为了或者指定类型的bd
的名称,之后通过bd
的名称去找到指定的bd
,然后获取对应的Bean,比如上面方法三次获取的都是BeanDefinitionRegistryPostProcessor
这个类型的bd
。
我们可以思考一下,为什么这一步需要合并呢?我们带着这个问题继续往下看
2、实例化
spring在实例化一个对象也会进行BeanDefinition的合并。
第一次:
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
//省略无关代码
// 循环bd,实例化单例bean
for (String beanName : beanNames) { // userService
// 对beanDefinition进行合并,基于合并后的BeanDefinition去创建bean
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
第二次:
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//省略无关代码
// 对beanName进行转换 name如果是"&lubanFactoryBean",那么beanName就是"lubanFactoryBean"
final String beanName = transformedBeanName(name);
Object bean;
if (sharedInstance != null && args == null) {
// 判断sharedInstance是不是FactoryBean,如果是FactoryBean,那么真正需要拿到的是getObject方法所返回的对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 原型bean正在创建中
// 当前BeanFactory中不存beanName对象的BeanDefinition,那么则从ParentBeanFactory中去获取
// 创建Bean
try {
// 得到合并后的BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
我们可以发现有一个共同的特点,就是在合并之后立马利用了合并后的BeanDefinition做了一系列的判断,比如mbd.getDependsOn()!=null等等,基于上面几个例子我们来分析,为什么需要合并?
为什么需要合并?
在扫描阶段,spring需要拿到指定了需要实现BeanDefinitionRegistryPostProcessor接口bd的名称,也就是说spring要用到bd的名称,所以进行了一次合并。在实例化阶段spring需要拿到bd的属性做判断,为了确保属性的正确性,所以进行了合并。
那么问题来了,为什么会存在获取属性不正确的呢?
这里主要有两点:
1、我们上面所说的父子bean的场景,有些属性只在父Bean中存在,所以需要合并
2、spring走生命周期的时候,可以通过spring的扩展点修改spring beanDefinition中的属性,所以需要合并
合并的代码分析
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// mbd.stale 这个是RootBeanDefinition的一个属性,决定了什么时候definition需要重新合并
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
// 如果bd的父bd为空
if (bd.getParentName() == null) {
// RootBeanDefinition没有父BeanDefinition
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
BeanDefinition pbd;
try {
// 父bd的beanName
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
//这里是递归需要确保父bd已经合并了
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
// 一般不会进这个判断
// 到父容器中找对应的bean,然后进行合并,合并也发生在父容器中
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
// pbd表示父BeanDefinition, bd表示本BeanDefinition
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd); // 把bd的属性设置给mbd, 而mbd是基于pbd来的,pbd是parent,bd是当前bd,把当前bd的属性设置给pbd就是合并(合并属性)
}
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// 如果某个<bean/>内包含了一个内部<bean/>,containingBd表示外部bean, mbd表示内部bean
// 外部bean如果不是单例bean,内部bean是单例的,那么则把内部bean的scope设置为和外部bean的scope一样的
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// 将合并后的bd放入到mergedBeanDefinitions这个map中
// 之后还是可能被清空的,因为bd可能被修改
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
上面这段代码不难理解,可能发生疑惑点
pbd = getMergedBeanDefinition(parentBeanName);
这里进行的是父bd的合并,这里是递归调用,可能存在的情况是父bd可能也不是一个最终合并后的bd
并后的bd放入到mergedBeanDefinitions这个map中
// 之后还是可能被清空的,因为bd可能被修改
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
上面这段代码不难理解,可能发生疑惑点
```java
pbd = getMergedBeanDefinition(parentBeanName);
这里进行的是父bd的合并,这里是递归调用,可能存在的情况是父bd可能也不是一个最终合并后的bd