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

Spring Boot循环中获取@Autowired原型Bean实例的实现方案咨询

带动态参数的原型Bean注入与单元测试解决方案

问题场景

刚接触Spring Boot,正在学习@Autowired注解、Dependency Injection(依赖注入)及单元测试,现有如下代码:

@Component
class A {
  public void classAMethod() {
    for(int i=0; i<10; i++) {
      B b = new B(dynamicStirngValue,dynamicIntValue, i);
      Object xyz = b.execute();
    }
  }
}

@Component
@Scope("prototype")
class B {

  public B(String str1, int int1, int int2) {
    // setting up the passed parameters
  }
  public Object execute() {
    // some code to use the class variables
  }
}

核心需求

  • 不使用new关键字,通过依赖注入获取B的实例,方便单元测试时Mock B的execute()方法;
  • B的带参构造器需支持传入动态参数(循环中每次参数不同);
  • classAMethod运行在多线程环境,每次必须获取B的新实例以避免并发问题,且不能用synchronized。

当前困境

通过构造器Mock时需要@PrepareForTest(A.class),导致代码覆盖率为0%,需要可行的替代方案。

解决方案

方法1:用Spring原生的ObjectFactory

直接借助ObjectFactory获取原型Bean实例,它天生支持传入动态构造参数,且每次调用都会返回新的原型实例。

修改后的A类代码:

@Component
class A {
    private final ObjectFactory<B> bFactory;

    // 构造注入ObjectFactory
    public A(ObjectFactory<B> bFactory) {
        this.bFactory = bFactory;
    }

    public void classAMethod() {
        for(int i=0; i<10; i++) {
            // 每次调用getObject生成新的B实例,同时传入动态参数
            B b = bFactory.getObject(dynamicStirngValue, dynamicIntValue, i);
            Object xyz = b.execute();
        }
    }
}

方法2:直接使用BeanFactory

如果觉得ObjectFactory不够直观,也可以注入BeanFactory,它的getBean方法同样支持传入构造参数,且对原型Bean每次调用都会生成新实例:

@Component
class A {
    private final BeanFactory beanFactory;

    public A(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public void classAMethod() {
        for(int i=0; i<10; i++) {
            B b = beanFactory.getBean(B.class, dynamicStirngValue, dynamicIntValue, i);
            Object xyz = b.execute();
        }
    }
}

单元测试实现(无需@PrepareForTest)

用Mockito即可完成Mock,不会影响代码覆盖率:

@ExtendWith(MockitoExtension.class)
class ATest {
    @Mock
    private BeanFactory beanFactory; // 若用ObjectFactory则Mock ObjectFactory即可

    @InjectMocks
    private A a;

    @Test
    void testClassAMethod() {
        // Mock B的实例
        B mockB = Mockito.mock(B.class);
        // 配置BeanFactory返回Mock实例
        when(beanFactory.getBean(B.class, anyString(), anyInt(), anyInt())).thenReturn(mockB);
        // 模拟execute方法的返回值
        when(mockB.execute()).thenReturn(new Object());

        // 执行测试方法
        a.classAMethod();

        // 验证调用次数
        verify(beanFactory, times(10)).getBean(B.class, anyString(), anyInt(), anyInt());
        verify(mockB, times(10)).execute();
    }
}

方案适配性说明

  • 规避直接new:通过Spring工厂类注入获取实例,符合依赖注入规范,测试时可轻松Mock;
  • 动态参数支持:getObject/getBean方法均支持传入构造参数,循环内动态传参无压力;
  • 多线程安全:B为原型作用域,每次获取都是全新实例,不存在线程共享状态,无需synchronized。

内容的提问来源于stack exchange,提问作者Akshay Borse

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:56:19