栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

什么是MergedBeanDefinition?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

什么是MergedBeanDefinition?

前言

MergedBeanDefinition是spring获取bean流程中的一个重要处理过程,他将基础的BeanDefinition合并为一个新的BeanDefinition对象(RootBeanDefinition),后续的处理过程都依赖这个新对象,

了解他有助于我们控制和管理bean实例化之前的行为。

在Spring 内部实际使用的BeanDefinition,其实都是合并后RootBeanDefinition对象,通过它进行

对象的实例化,注入等。我们需要关注这个过程,这将决定Bean的产生。

知识铺垫

什么是Spring BeanDefinition?

什么是Spring BeanDefinition我就不解释了。这属于Spring的常识知识!

Spring有哪些BeanDefinition?他们有什么区别,以下列出部分重要的BeanDefinition

ConfigurationClassBeanDefinition(@Bean标注的产生)

AnnotatedGenericBeanDefinition(@Configuration标注的)

ScannedGenericBeanDefinition(通过@ComponentScan扫描或扫描行为产生的,注:理论上你实现自己的扫描行为,那么你可以自主选择具体的BeanDefinition实现类。)

RootBeanDefinition(Spring最终使用的BeanDefinition,其他BeanDefinition都会转换为它)

MergedBeanDefinition过程解析
//AbstractBeanFactory.java
protected  T doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

    //以上省略若干行

    //获取合并的Beandefinition,实际是产生一个RootBeanDefinition
    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

    //检查RootBeanDefinition的有效性,后续的代码会使用这个产生的RootBeanDefinition 
	checkMergedBeanDefinition(mbd, beanName, args);
    
    //以下省略若干行
}

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    // Quick check on the concurrent map first, with minimal locking.
    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)
			throws BeanDefinitionStoreException {

		return getMergedBeanDefinition(beanName, bd, null);
}
protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
			throws BeanDefinitionStoreException {

        //辗转反侧最后调用的是这个方法,具体代码太多,省略
        //你只需要最终各种操作之后得到了RootBeanDefinition 
}

解析了这么多源码,只明白了,原来原始的BeanDefinition最终会转换为RootBeanDefinition,奇怪的知识增加了,但是好像觉得没有什么用,这个时候可以提出一个需求,造出一个场景,让这段知识排上用场。

假设,现在有一个接口,他有多个实现类,并且都没有指定@Primary,在注入接口的类也没有指定@Qualifier限定操作,如何动态选择一个实例的注入到Bean?

应用场景 

通过源码观察,Spring提供了一个可供操作合并后RootBeanDefinition的扩展点(后置处理器),通过这个扩展点,可以实现对RootBeanDefinition的操作

实现上述假设:

public interface Say {
    String tell();
}

@Component
public class CatSay implements Say  {
    @Override
    public String tell() {
        return "cat";
    }
}

@Component
public class DogSay implements Say {
    @Override
    public String tell() {
        return "dog";
    }
}

@Component
public class Zoo{
    //注入,如果不做一些介入,那么必然是报错的
    @Autowired
    private Say say;
}


public static void main( String[] args ){
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    Zoo zoo = context.getBean(Zoo.class);
}


//为了不报错,比如引入如下操作


@Component
public class MergedBeanDefinitionPostProcess implements MergedBeanDefinitionPostProcessor, ApplicationContextAware {

    private ApplicationContext applicationContext = null;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
        if(CatSay.class.equals(beanType)){
            
            
            beanDefinition.setPrimary(true);

            ConfigurableListableBeanFactory app = (ConfigurableListableBeanFactory) this.applicationContext.getAutowireCapableBeanFactory();
            BeanDefinition definition = app.getBeanDefinition(beanName);
            definition.setPrimary(true);
            
            
        }
    }
}

总结

Spring的MergedBeanDefinition过程非常重要,它揭示了Spring最终是如何运用Bean元数据产生Bean的,通过例子的引申,我们可以通过 MergedBeanDefinitionPostProcessor接口做很多有意思的事情,它是改变Bean元数据的一个重要窗口。

其实不止这一个窗口,BeanDefinitionRegistryPostProcessor接口也可以改变BeanDefinition,不过他发生的时机是原始BeanDefinition构建完毕,所以只能改变原始的BeanDefinition。

最后,如果你想动态改变BeanDefinition,控制Bean的行为,可以用如下2个扩展点

扩展点用途
BeanDefinitionRegistryPostProcessor
可以更改原始BeanDefinition
MergedBeanDefinitionPostProcessor
可以更改RootBeanDefinition

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/390133.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号