You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在测试类中实例化并向Spring ApplicationContext注册Bean以被主类识别?

问题分析

核心问题出在两个关键点:

  1. 多上下文隔离:测试类同时通过@SpringBootTest启动了一个Spring Boot上下文,又在构造函数里手动创建了AnnotationConfigApplicationContext,两个上下文完全独立。你把动态Bean注册到了手动创建的上下文,但ClassFromMainCode要么依赖@SpringBootTest的上下文,要么是你手动new的未被Spring管理的实例,自然检测不到跨上下文的Bean。
  2. 手动实例化的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 01:07:47