[英]Spring JUnit4 manual-/auto-wiring dilemma
我遇到了一个问题,该问题只能由我对Spring的IoC容器功能和上下文设置缺乏基本了解的情况来解释,因此,我要求对此进行澄清。
仅供参考,我维护的应用程序具有以下技术堆栈:
我回溯地(原文如此!)为应用程序编写了JUnit测试,令我惊讶的是,我无法通过使用setter注入来将bean注入测试类中,而没有使用@Autowire表示法。
让我提供一个示例和随附的配置文件。
测试类TypeTest
非常简单:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TypeTest {
@Autowired
private IType type;
@Test
public void testFindAllTypes() {
List<Type> result;
try {
result = type.findAlltTypes();
assertNotNull(result);
} catch (Exception e) {
e.printStackTrace();
fail("Exception caught with " + e.getMessage());
}
}
}
它的上下文在TestStackOverflowExample-context.xml
定义:
<context:property-placeholder location="classpath:testContext.properties" />
<context:annotation-config />
<tx:annotation-driven />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db.connection.driver.class}" />
<property name="url" value="${db.connection.url}" />
<property name="username" value="${db.connection.username}" />
<property name="password" value="${db.connection.password}" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="beanDAO" class="com.example.BeanDAOImpl">
<property name="ds" ref="dataSource"></property>
<property name="beanDAOTwo" ref="beanDAOTwo"></property>
</bean>
<bean id="beanDAOTwo" class="com.example.BeanDAOTwoImpl">
<property name="ds" ref="dataSource"></property>
</bean>
<bean id="type" class="com.example.TypeImpl">
<property name="beanDAO" ref="beanDAO"></property>
</bean>
TestContext.properties
在类路径中,并且仅包含数据源所需的特定于数据库的数据。
这就像一个咒语,但我的问题是-为什么当我尝试手动连接bean并执行setter注入时,为什么它不起作用:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TypeTest {
private IType type;
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
@Test
public void testFindAllTypes(){
//snip, snip...
}
}
我在这里想念什么? 此处哪部分配置错误? 当我尝试通过设置器手动注入bean时,测试失败,因为这部分
result = type.findAlltTypes();
在运行时解析为null。 当然,我已经查阅了Spring参考手册,并尝试了XML配置的各种组合。 我只能得出的结论是,Spring无法注入bean,因为它某种程度上无法正确地取消对Spring Test Context引用的引用,但是通过使用@Autowired,它“自动地”发生了,我真的看不到为什么,因为Autowired
注释和它的PostProcessor
类没有提到这一点。
另外值得一提的是,@ @Autowired
仅在此处用于应用程序。 在其他地方,仅执行手动接线,所以这也带来了一个问题-在我的测试中,为什么在那儿工作而不在这里工作? 我缺少DI配置的哪一部分? @Autowired
如何获取Spring Context的引用?
编辑:我也尝试了此但具有相同的结果:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TypeTest implements ApplicationContextAware{
private IType type;
private ApplicationContext ctx;
public TypeTest(){
super();
ctx = new FileSystemXmlApplicationContext("/TypeTest-context.xml");
ctx.getBean("type");
}
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
@Test
public void testFindAllTypes(){
//snip, snip...
}
}
还有其他想法吗?
EDIT2:我找到了一种无需编写自己的TestContextListener
或BeanPostProcessor
。 这非常简单,原来我上次编辑的位置正确:
1)基于构造函数的上下文解析:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TypeTest{
private IType type;
private ApplicationContext ctx;
public TypeTest(){
super();
ctx = new FileSystemXmlApplicationContext("/TypeTest-context.xml");
type = ctx.getBean("type");
}
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
@Test
public void testFindAllTypes(){
//snip, snip...
}
}
2)通过实现ApplicationContextAware接口:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TypeTest implements ApplicationContextAware{
private IType type;
private ApplicationContext ctx;
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.ctx = ctx;
type = (Type) ctx.getBean("type");
}
@Test
public void testFindAllTypes(){
//snip, snip...
}
}
这两种方法都正确地实例化了bean。
如果查看org.springframework.test.context.support.DependencyInjectionTestExecutionListener
的源,您将看到以下方法(为清晰起见,对其进行了格式化和注释):
protected void injectDependencies(final TestContext testContext)
throws Exception {
Object bean = testContext.getTestInstance();
AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext()
.getAutowireCapableBeanFactory();
beanFactory.autowireBeanProperties(bean,
AutowireCapableBeanFactory.AUTOWIRE_NO,
// no autowiring!!!!!!!!
false
);
beanFactory.initializeBean(bean, testContext.getTestClass().getName());
// but here, bean post processors are run
testContext.removeAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE);
}
因此,测试对象是没有自动装配的bean。 但是, @AutoWired
, @Resource
等不使用自动装配机制,它们使用BeanPostProcessor
。 因此,只有且仅当使用了注释时(或如果您注册执行此操作的其他其他BeanPostProcessor
,才会注入依赖项。
(上面的代码来自Spring 3.0.x,但我敢打赌,它在2.5.x中是相同的)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.