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

Spring 6+JUnit 5中嵌套@Autowired依赖测试时无法注入

Spring 6 + JUnit 5集成测试:嵌套@Autowired依赖注入失败的解决办法

问题根因

你在ExchangeCacheImpl.loadAll()里直接new ExchangeImpl()创建的对象不在Spring容器管控范围内,Spring不会自动处理它内部的@Autowired依赖注入。生产环境正常是因为生产环境中ExchangeImpl是由Spring容器实例化的(比如通过Bean定义、工厂Bean等),而非手动new出来的。

可行解决方案

1. 让Spring接管ExchangeImpl的实例化

把ExchangeImpl声明为Spring Bean(加@Component注解,或者在配置类里用@Bean定义),然后在ExchangeCacheImpl中注入ObjectProvider<ExchangeImpl>来获取实例,替代手动new:

@Component
public class ExchangeCacheImpl implements ExchangeCache {
    private final ObjectProvider<ExchangeImpl> exchangeProvider;

    // 构造注入ObjectProvider
    public ExchangeCacheImpl(ObjectProvider<ExchangeImpl> exchangeProvider) {
        this.exchangeProvider = exchangeProvider;
    }

    public void loadAll() {
        // 用Spring提供的方式创建实例,Spring会自动注入内部依赖
        ExchangeImpl exchange = exchangeProvider.getObject();
        // 后续业务逻辑...
    }
}

同时确保ExchangeImpl上标注了@Component(或者在配置类中定义为Bean),并且它依赖的ExchangeIrregularHoursDAO、ExchangeRegularHoursDAO已经被Spring管理。

2. 测试中手动触发依赖注入

如果不想改动太多业务代码,可以在测试类里拿到ApplicationContext,手动调用Spring的AutowireCapableBeanFactory来给ExchangeImpl注入依赖:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {YourAppConfig.class})
public class ExchangeDBTest {
    @Autowired
    private ApplicationContext ctx;
    @Autowired
    private ExchangeCache exchangeCache;

    @Test
    public void testLoadAll() {
        // 执行loadAll逻辑后,需要从exchangeCache里拿到创建的ExchangeImpl实例
        // 这里需要ExchangeCacheImpl临时加个get方法暴露实例,测试完可以删掉或者改成包私有
        ExchangeImpl exchange = ((ExchangeCacheImpl) exchangeCache).getCreatedExchange();
        
        // 手动触发Spring的依赖注入
        ctx.getAutowireCapableBeanFactory().autowireBean(exchange);
        
        // 现在调用exchange.getStandardClose(date)就不会空指针了
        // 后续测试逻辑...
    }
}

这个方案不需要修改ExchangeImpl,适合快速验证测试场景。

3. 用@Configurable+编译时织入实现自动注入

如果必须保留手动new ExchangeImpl()的写法,又想让Spring自动注入依赖,可以给ExchangeImpl加@Configurable注解,同时开启Spring的编译时织入:

@Configurable
public class ExchangeImpl {
    @Autowired
    private ExchangeIrregularHoursDAO irregularHoursDAO;
    @Autowired
    private ExchangeRegularHoursDAO regularHoursDAO;
    // 业务方法...
}

然后在Spring配置类中开启织入支持:

@Configuration
@ComponentScan
@EnableSpringConfigured
public class AppConfig {
    // 其他配置...
}

这种方式需要配置编译时织入(比如用AspectJ的Maven插件),对项目构建流程有要求,但不需要修改实例化代码。

踩坑提醒

  • 之前尝试的原型Bean方案无效,是因为你还是用new创建实例,没有通过Spring容器获取原型Bean。必须通过context.getBean(ExchangeImpl.class)或者ObjectProvider来获取,Spring才会处理依赖注入。
  • 测试类的@ContextConfiguration要确保包含所有必要的配置类,比如DAO层的配置、Bean扫描配置等,不然Spring找不到依赖的Bean。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:41:09