测试中的Bean覆盖
在测试中覆盖Bean(Bean overriding in tests)指的是通过为测试类或测试类中的一个或多个非静态字段添加注解,来覆盖ApplicationContext中的特定Bean的能力。
此功能旨在作为一种风险较低的替代方案,用于通过@Bean注册bean,同时将DefaultListableBeanFactory的setAllowBeanDefinitionOverriding标志设置为true。
Spring TestContext框架提供了两组用于bean覆盖的注解。
前者完全依赖于Spring,而后者则依赖于[Mockito](https://site Mockito.org/)这个第三方库。
自定义Bean覆盖支持
上述三种注解都是基于@BeanOverride元注释及其相关基础设施构建的,这种元注释允许用户定义自定义的bean覆盖变体。
为了实现自定义bean覆盖支持,需要以下内容:
- 一个带有
@BeanOverride元注释的注解,用于定义要使用的BeanOverrideProcessor - 一个自定义的
BeanOverrideProcessor实现 - 由该处理器创建的一个或多个具体的
BeanOverrideHandler实现
Spring TestContext框架包含了以下API的实现,这些API支持bean覆盖(bean overriding),并负责设置其余的基础设施。
- 一个
BeanFactoryPostProcessor - 一个
ContextCustomizerFactory - 一个
TestExecutionListener
spring-test模块在它的META-INF/spring.factories属性文件中注册了后两个类(BeanOverrideContextCustomizerFactory和BeanOverrideTestExecutionListener)的实现。
Bean覆盖基础设施会搜索测试类上的注解,以及测试类中带有@BeanOverride元注释的非静态字段上的注解,然后实例化相应的BeanOverrideProcessor,该处理器负责创建适当的BeanOverrideHandler。
内部的BeanOverrideBeanFactoryPostProcessor随后会使用bean覆盖处理器来修改测试的ApplicationContext,通过创建、替换或包装bean来实现这一目标,具体操作方式由相应的BeanOverrideStrategy定义:
REPLACE
替换该bean。如果不存在相应的bean,则会抛出异常。
REPLACE_OR_CREATE
如果该bean存在,则替换它;如果不存在相应的bean,则创建一个新的bean。
WRAP
检索原始bean并将其包装起来。
在替换非单例bean时,该非单例bean将被替换为由相应的BeanOverrideHandler创建的单例bean实例,且对应的bean定义也将被转换为singleton类型。因此,如果某个处理器覆盖了prototype或scoped类型的bean,那么被覆盖的bean将被视为singleton。
当替换由FactoryBean创建的bean时,FactoryBean本身将被替换为由相应的BeanOverrideHandler创建的单例bean实例。
当对由FactoryBean创建的bean进行包装时,被包装的是FactoryBean创建的对象本身,而不是FactoryBean本身。
与Spring的自动装配机制(例如,@Autowired字段的解析)不同,TestContext框架中的Bean覆盖基础设施在定位bean时可使用的启发式方法较为有限。BeanOverrideProcessor要么可以计算出需要覆盖的bean的名称,要么可以根据被注解字段的类型及其附加注解来明确地选择该bean。
通常,BeanOverrideFactoryPostProcessor会“按类型”来选择bean。另外,用户也可以在自定义注解中直接提供bean的名称。
BeanOverrideProcessor的实现也可能基于某种约定或其他方法在内部计算bean的名称。