返回

抛开底层探索 ImportBeanDefinitionRegistrar与ImportSelector,再谈@ConditionalOnBean

后端

好的,以下就是根据您提供的输入,为您生成的文章:

抛开底层探索 ImportBeanDefinitionRegistrar与ImportSelector,再谈@ConditionalOnBean

引言

最近在给公司写一些组件,自然会用到比较多的Spring拓展类,遇到一个奇异问题,结合Spring Bean创建过程,记录一下排查解决思路,现象:

  • 使用到ImportBeanDefinitionRegistrar和ImportSelector导致@ConditionalOnBean失效。

问题的原因在于使用import导致了多次beanDefinition的加载,这才造成@ConditionalOnBean 失效。那我们如何使ConditionalOnBean生效呢,就需要讲到Bean的整个生命周期了。

Bean的生命周期

1. 扫描加载BeanDefinition

BeanDefinition是Bean的元信息,也就是说,这个Bean要创建成什么样子。其由各个BeanDefinitionReader去加载到IoC容器之中。

2. BeanDefinition注册

在Bean创建之前,Bean的定义信息BeanDefinition会被先注册进BeanDefinitionRegistry。

3. Bean创建

根据BeanDefinition 创建真正的Bean。

这三个步骤构成了Bean的整个生命周期。

回到ImportBeanDefinitionRegistrar和ImportSelector的问题

根据ImportBeanDefinitionRegistrar和ImportSelector的源码,我们可以知道,这两个接口的实现类本质上都是BeanDefinitionRegistryPostProcessor ,这是BeanFactory的后置处理器,其在Bean创建之前,将相应的BeanDefinition注册到BeanDefinitionRegistry,所以重复加载了。

而@ConditionalOnBean,顾名思义,Bean有没有加载,是由这个注解决定的,ImportBeanDefinitionRegistrar和ImportSelector却在Bean创建之前就已经把这个Bean注册进去了。

解决方法

解决这个问题的方法也很简单,就是让ImportBeanDefinitionRegistrar和ImportSelector先于@ConditionalOnBean加载即可,如果我们在Bean所在的类上加上@DependsOn注解,指定一个使用ImportBeanDefinitionRegistrar和ImportSelector的类,@ConditionalOnBean将先于这两个类加载,问题就可以解决了。

结语

本文通过对ImportBeanDefinitionRegistrar和ImportSelector导致@ConditionalOnBean失效问题的分析,深入探讨了Spring bean创建过程,特别是ImportBeanDefinitionRegistrar和ImportSelector的作用。我们还提供了清晰的示例和代码,帮助读者理解这些概念并在自己的项目中应用。对于希望深入理解Spring bean创建过程和自定义bean加载的开发者来说,这篇文章具有很高的参考价值。

希望这篇文章对您有所帮助!