spring

MergedBeanDefinition分析

2019-11-17  本文已影响0人  loveFXX

applyMergedBeanDefinitionPostProcessors方法

在bean的生命周期中,第三次后置处理器调用使用了MergedBeanDefinition
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);,应用合并BeanDefinition的后置处理器此方法主要缓存一些带了注解的属性字段例如@Autowired、@Common等元数据注入信息

示例代码

package com.mergebd;
@Component
public class A {
}

package com.mergebd;
public class ChildBean {
        @Autowired
         A a;
    private String contry;
    private String city;
    public String getContry() {
        return contry;
    }
    public void setContry(String contry) {
        this.contry = contry;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    @Override
    public String toString() {
        return "contry="+contry+" city="+city;
    }
}


package com.mergebd;
public class RootBean {
    private String contry;
    private String city;

    public String getContry() {
        return contry;
    }
    public void setContry(String contry) {
        this.contry = contry;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    @Override
    public String toString() {
        return "contry="+contry+" city="+city;
    }
}


package com.mergebd;
@Configuration
@ComponentScan("com.mergebd")
public class MergeAppConfig {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac =
                new AnnotationConfigApplicationContext();
        ac.register( MergeAppConfig.class );

        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(  );
        rootBeanDefinition.setBeanClass( RootBean.class);
        rootBeanDefinition.getPropertyValues().add( "contry","zh" );
        rootBeanDefinition.getPropertyValues().add( "city","beijing" );
        ac.registerBeanDefinition( "root",rootBeanDefinition );

        GenericBeanDefinition genericBeanDefinition =new GenericBeanDefinition(  );
        genericBeanDefinition .setBeanClass( ChildBean.class);
        genericBeanDefinition.setParentName( "root" );
        genericBeanDefinition.getPropertyValues().add( "city","shenzhen" );
        ac.registerBeanDefinition( "child",genericBeanDefinition );

        ac.refresh();
        System.out.println( ac.getBean( "child" ).toString() );
    }
}

degub分析结果

applyMergedBeanDefinitionPostProcessors方法


applyMergedBeanDefinitionPostProcessors.png

由于BeanDefinition有各种实现类,且实现类能指定'父子'依赖信息的关系(不是继承关系,仅仅是指定数据的父子关系)。如果元数据依赖不合并的话,则这个beanDefinition的元数据信息将不完整。

合并的BeanDefinition测试结果

ChildBean并没有赋值contry属性,返回结果含contry是zh,city是shenzhen。说明了进行Merge合并


merge.png

调用链

AbstractApplicationContext#refresh
AbstractApplicationContext#invokeBeanFactoryPostProcessors
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, List<BeanFactoryPostProcessor>)
DefaultListableBeanFactory#getBeanNamesForType(Class<?>, boolean, boolean)
DefaultListableBeanFactory#doGetBeanNamesForType

debug分析

doGetBeanNamesForType

根据beanDefinitionNames遍历所有


doGetBeanNamesForType.png

getMergedLocalBeanDefinition

mergedBeanDefinitions集合在当前BeanName第一次调用到这里肯定为null


getMergedLocalBeanDefinition.png

getMergedBeanDefinition

getMergedBeanDefinition.png

getParentName

mergedBeanDefinitions经过以上步骤,这里也是null。然后判断当前BeanDefinition的ParentName是否为null


getParentName.png

parentName

获取parentName的BeanDefinition


parentName.png

getMergedBeanDefinitionpbd

parentName也经过getMergedBeanDefinitionpbd方法判断是否具有parentName属性


getMergedBeanDefinitionpbd.png

override

以parentBeanDefinition作为基准,子BeanDefinition复制到parentBeanDefinition


deepcopy.png
setBeanClass设置Bean类
setBeanClass.png
setPropertyValues设置属性值
setPropertyValues.png
PropertyValues属性值覆盖
copyvalues.png

经过一系列其他的BeanDefinition的属性值赋值给父BeanDefinition,最终把这个父BeanDefinition用put到mergedBeanDefinitions,完成了child此时的属性合并(此时的BeanDefinition不一定是最终的,当然在示例代码是最终的)

其他地方调用getMergedLocalBeanDefinition方法

preInstantiateSingletons

DefaultListableBeanFactory#preInstantiateSingletons在准备实例化单例对象,经过遍历BeanNames会从mergedBeanDefinitions(此时应该不会为null)获取合成的BeanDefinition


preInstantiateSingletons.png

createBean

在创建Bean之前,清除合成BeanDefinition集合。需要重新获取
执行到AbstractBeanFactory#doGetBean
typeCheckOnly默认是false


markBeanAsCreated.png
clearMergedBeanDefinition

从mergedBeanDefinitions集合remove当前beanName。并添加到alreadyCreated正在创建集合中。之后再次调用getMergedLocalBeanDefinition方法,重新获取一遍合成BeanDefinition


clearMergedBeanDefinition.png

总结:

由于BeanDefinition的实现子类可以指定“父子关系”。MergedBeanDefinition就是表示如何正确获取合成BeanDefinition属性值
关键点:
1、getMergedLocalBeanDefinition方法执行时机
2、mergedBeanDefinitions集合
后置处理器方法applyMergedBeanDefinitionPostProcessors 的BeanDefinition都是MergedBeanDefinition(合成的) 作用是缓存注解信息

上一篇下一篇

猜你喜欢

热点阅读