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 protectedT 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 |



