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

使用ApplicationContextRunner时自动配置未执行的问题排查

自定义Spring Boot自动配置类Bean加载失败问题排查与解决

问题场景

测试自定义CompanyHttpClientAutoConfiguration自动配置类,期望通过该类扫描指定包加载Registrar,进而注册带有@CompanyHttpClient注解的Bean,但测试时发现SomeHttpClient实例无法被Spring上下文识别,抛出NoSuchBeanDefinitionException。

测试代码

public class CompanyHttpClientAutoConfigurationTest {

    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(CodecsAutoConfiguration.class, ClientHttpConnectorAutoConfiguration.class, WebClientAutoConfiguration.class, CompanyHttpClientAutoConfiguration.class));

    @Test
    public void httpClientInjected(){
        //ARRANGE
        //ACT
        //ASSERT
        this.contextRunner.withPropertyValues("org.company.http.clients.someHttpClient.baseUrl=http://localhost:8080").run(context -> assertNotNull(context.getBean(SomeHttpClient.class)));
    }

    @CompanyHttpClient(name = "someHttpClient")
    interface SomeHttpClient{
        @GetExchange
        String get();
    }
}

自动配置类代码

@Configuration
@AutoConfigureAfter(WebClientAutoConfiguration.class)
@ComponentScan("org.company.http")
@ConditionalOnBean(WebClient.Builder.class)
public class CompanyHttpClientAutoConfiguration {
}

错误日志

19:10:05.452 [Test worker] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext -- Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@6bb75258
19:10:05.459 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
...(省略中间冗余日志)
19:10:05.669 [Test worker] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext -- Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@6bb75258, started on Sun May 28 19:10:05 EDT 2023

No qualifying bean of type 'org.company.http.autoconfig.companyHttpClientAutoConfigurationTest$SomeHttpClient' available
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.company.http.autoconfig.companyHttpClientAutoConfigurationTest$SomeHttpClient' available

问题原因与解决方法

核心原因

  1. 自动配置类的@ComponentScan("org.company.http")仅扫描指定包下的组件,但测试用的SomeHttpClient是测试类的内部类,不在该扫描范围内,负责处理@CompanyHttpClient注解的Registrar无法发现这个接口。
  2. 虽然日志显示自动配置类已被加载,但Registrar只能处理扫描范围内的注解类,无法感知测试类内部的接口。

具体解决步骤

方案一:将测试接口移至扫描包下

把SomeHttpClient接口从测试类内部移出,放到org.company.http包或其子包下,让@ComponentScan能扫描到该接口,Registrar会自动处理注解并生成Bean实例。

方案二:测试中手动注册接口实例

若不想移动接口,可在测试中通过ApplicationContextRunner手动注册Bean:

@Test
public void httpClientInjected(){
    this.contextRunner.withPropertyValues("org.company.http.clients.someHttpClient.baseUrl=http://localhost:8080")
            // 替换为实际创建SomeHttpClient实例的逻辑,比如用你的Registrar或工厂类
            .withBean(SomeHttpClient.class, () -> YourHttpClientFactory.createProxy(SomeHttpClient.class))
            .run(context -> assertNotNull(context.getBean(SomeHttpClient.class)));
}

方案三:扩展测试上下文的扫描范围

在测试中添加自定义配置类,扩展组件扫描范围到测试类所在包:

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
        .withConfiguration(AutoConfigurations.of(CodecsAutoConfiguration.class, ClientHttpConnectorAutoConfiguration.class, WebClientAutoConfiguration.class, CompanyHttpClientAutoConfiguration.class))
        .withUserConfiguration(TestScanConfig.class);

@Configuration
@ComponentScan(basePackageClasses = CompanyHttpClientAutoConfigurationTest.class)
static class TestScanConfig {}

额外验证点

  • 从日志可知webClientAutoConfiguration已加载,WebClient.BuilderBean存在,自动配置类的@ConditionalOnBean条件已满足,无需担心条件不触发问题。
  • 确认处理@CompanyHttpClient的Registrar类在org.company.http包下,确保@ComponentScan能扫描到Registrar本身,否则注解处理逻辑根本不会生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:22:03