【问题标题】:Spring @Autowired behavior different in tests than componentsSpring @Autowired 在测试中的行为与组件不同
【发布时间】:2018-12-02 02:51:09
【问题描述】:

在编写测试时,@Autowired 周围的规则/行为是否不同?似乎通过测试,您可以自动连接到具体类型,但如果您在 @Component 中尝试相同的事情,它将失败。这是一个人为的例子,但这是我遇到的,只是想更好地理解。

人为的示例代码:

public interface Gizmo {

  void whirr();
}

@Configuration
public class GizmoConfiguration {

  @Bean
  @Profile("no-dependencies")
  public Gizmo fooGizmoBean() {
    return new FooGizmo();
  }

  @Bean
  @Profile("!no-dependencies")
  public Gizmo barGizmoBean() {
    return new BarGizmo();
  }

  public class FooGizmo implements Gizmo {
    @Override
    public void whirr() {
    }
  }

  public class BarGizmo implements Gizmo {
    @Override
    public void whirr() {
    }
  }
}

测试运行良好:

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles(Application.Profiles.NO_DEPENDENCIES)
public class TestClass {

  @Autowired
  private GizmoConfiguration.FooGizmo gizmo;

  @Test
  public void test() {
    assertNotNull(gizmo);
  }
}

导致java.lang.IllegalStateException: Failed to load ApplicationContext的组件:

@Component
public class TestComponent {

  @Autowired
  private GizmoConfiguration.FooGizmo gizmo;
}

因为:

No qualifying bean of type 'GizmoConfiguration$FooGizmo' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

【问题讨论】:

    标签: spring spring-test spring-ioc


    【解决方案1】:

    在编写时,@Autowired 周围的规则/行为是否不同? 测试?

    不完全一样:规则实际上是完全一样的。不同之处在于 Spring 如何确定给定 bean 是否是自动装配候选者的时间。

    似乎通过测试,您可以自动装配到具体类型, 但是如果你在 @Component 中尝试同样的事情,它会失败。

    我理解你为什么会这样想,因为你的例子证明了这种行为,但你的分析并不完全正确。

    让我解释一下……

    当 Spring 尝试为您的 @Component 类执行自动装配时,它拥有的关于来自 @Bean 方法的 bean 的类型(即类和接口)的唯一信息是 @Bean 方法的正式签名中可用的信息.

    在您的示例中,当 Spring 搜索所谓的“自动装配候选者”以注入您的 @Component 时,Spring 只会为您的 fooGizmoBean() @Bean 方法看到 Gizmo 类型的 bean。所以这就是为什么您会看到“No qualifying bean of type 'GizmoConfiguration$FooGizmo'”错误,这恰好是完全正确的。

    如果您希望 Spring 能够使用具体类型自动连接您的 @Component,则必须重新定义 fooGizmoBean() @Bean 方法的签名以返回 FooGizmo 而不是 Gizmo

    所以,这就是故事的前半部分。故事的后半部分是为什么 Spring TestContext Framework 能够通过测试实例的具体类型执行自动装配。

    有效的原因是,当测试框架尝试执行依赖注入时,ApplicationContext 已经完全启动(即所有 bean 都已实例化,并且容器已调用所有 @Bean 方法) .到那时,fooGizmoBean() 方法已经被 Spring 调用了,Spring 现在知道具体类型实际上是 FooGizmo。因此,@Autowired FooGizmo gizmo; 在测试中有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-19
      • 2020-11-04
      • 2018-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多