编写测试时,@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)}
答案 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
在测试中起作用。