Spring @Autowired行为在测试中与组件不同

时间:2018-06-22 15:21:41

标签: spring spring-test spring-ioc

编写测试时,@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)}

1 个答案:

答案 0 :(得分:13)

  

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

不完全相同:规则实际上完全相同。区别在于在Spring确定给定bean是否为自动装配候选方面的时间安排上。

  

似乎通过测试,您可以自动装配为具体类型,   但是如果您在@Component内尝试相同的操作,它将失败。

我理解您为什么会这样认为,因为您的示例演示了这种行为,但是您的分析并不完全正确。

所以让我解释一下...

当Spring尝试为您的@Component类执行自动装配时,它唯一有关来自@Bean方法的bean类型(即类和接口)的信息就是{{ 1}}方法的正式签名。

在您的示例中,当Spring搜索要注入到您的@Bean的所谓的“自动布线候选者”时,Spring只会看到@Component {{1 }} 方法。因此,这就是为什么您看到“完全没有问题的'GizmoConfiguration $ FooGizmo类型的合格bean”错误的原因。

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

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

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