如何在测试类中实例化并向Spring ApplicationContext注册Bean以被主类识别?
问题分析
核心问题出在两个关键点:
- 多上下文隔离:测试类同时通过
@SpringBootTest启动了一个Spring Boot上下文,又在构造函数里手动创建了AnnotationConfigApplicationContext,两个上下文完全独立。你把动态Bean注册到了手动创建的上下文,但ClassFromMainCode要么依赖@SpringBootTest的上下文,要么是你手动new的未被Spring管理的实例,自然检测不到跨上下文的Bean。 - 手动实例化的Bean无依赖注入:
new ClassFromMainCode()创建的对象不受Spring容器管控,它的@Autowired字段applicationContext不会被注入,本质上是无效的依赖引用。
修复方案
方案一:统一使用@SpringBootTest的上下文
修改测试类,复用@SpringBootTest启动的上下文,同时使用Spring管理的ClassFromMainCode实例:
@SpringBootTest( classes = { ClassFromMainCode.class }, webEnvironment = SpringBootTest.WebEnvironment.NONE ) public class SampleTestClass { // 注入SpringBootTest启动的上下文 @Autowired private ConfigurableApplicationContext applicationContext; // 注入Spring容器管理的ClassFromMainCode实例 @Autowired private ClassFromMainCode classFromMainCode; @Test public void testCase1() { String beanName = "abc"; Class<?> beanClass = String.class; registerSpringBean(beanName, beanClass); // 现在会返回True assert classFromMainCode.isBean(beanName); // 同一上下文,同样返回True assert this.applicationContext.containsBean(beanName); } private void registerSpringBean(String beanName, Class<?> beanClass) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext; GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(beanClass); registry.registerBeanDefinition(beanName, beanDefinition); // 触发Bean实例化,确保上下文识别到新注册的Bean applicationContext.getBean(beanName); } }
关键修改点
- 移除手动创建的
ApplicationContext,直接注入@SpringBootTest提供的上下文,保证所有操作在同一个容器内进行。 - 通过
@Autowired获取ClassFromMainCode的Spring管理实例,其内部的applicationContext会被自动注入为当前测试上下文。 - 注册BeanDefinition后调用
getBean()触发实例化,避免Spring Boot上下文启动后无法直接refresh()的问题。
方案二:手动创建上下文并统一管理所有Bean
如果需要完全手动控制上下文,需将ClassFromMainCode也注册到手动上下文,并从该上下文中获取实例:
public class SampleTestClass { private ConfigurableApplicationContext applicationContext; @BeforeEach public void setup() { applicationContext = new AnnotationConfigApplicationContext(); // 将ClassFromMainCode注册到手动上下文 applicationContext.register(ClassFromMainCode.class); applicationContext.refresh(); } @Test public void testCase1() { String beanName = "abc"; Class<?> beanClass = String.class; registerSpringBean(beanName, beanClass); // 从手动上下文中获取ClassFromMainCode实例 ClassFromMainCode classFromMainCode = applicationContext.getBean(ClassFromMainCode.class); // 现在返回True assert classFromMainCode.isBean(beanName); assert this.applicationContext.containsBean(beanName); } private void registerSpringBean(String beanName, Class<?> beanClass) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext; GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(beanClass); registry.registerBeanDefinition(beanName, beanDefinition); applicationContext.getBean(beanName); } }
这样所有Bean和依赖都处于同一个手动上下文,就能正确检测到动态注册的Bean。
内容的提问来源于stack exchange,提问作者software-surgeon
相关产品推荐
相关产品推荐

