qua*_*tum 5 java spring ioc-container junit4 autowired
我遇到了一个问题,这个问题只能解释为我对Spring的IoC容器设施和上下文设置缺乏了解,所以我会要求澄清一下.
仅供参考,我正在维护的应用程序具有以下堆栈技术:
我追溯(sic!)为应用程序编写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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
其背景定义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>
Run Code Online (Sandbox Code Playgroud)
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...
}
}
Run Code Online (Sandbox Code Playgroud)
我在这里错过了什么?配置的哪一部分在这里有误?当我尝试通过setter手动注入bean时,测试失败,因为这部分
result = type.findAlltTypes();
Run Code Online (Sandbox Code Playgroud)
在运行时被解析为null.当然,我参考了Spring参考手册并尝试了各种XML配置组合; 我可以得出的结论是,Spring无法注入bean,因为它无法正确地取消引用Spring Test Context引用,但是使用@Autowired这种情况"自动地"发生了,我真的不明白为什么会这样,因为JavaDoc都是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...
}
}
Run Code Online (Sandbox Code Playgroud)
或许还有其他想法吗?
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...
}
}
Run Code Online (Sandbox Code Playgroud)
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...
}
}
Run Code Online (Sandbox Code Playgroud)
这两种方法都适当地实例化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);
}
Run Code Online (Sandbox Code Playgroud)
因此测试对象是没有自动布线的bean.然而@AutoWired,@Resource等,不使用时自动连接机制,他们使用BeanPostProcessor.因此,当且仅当使用注释时(或者如果您注册其他一些注释),依赖项将被注入BeanPostProcessor.
(上面的代码来自Spring 3.0.x,但我敢打赌它在2.5.x中是相同的)
| 归档时间: |
|
| 查看次数: |
2733 次 |
| 最近记录: |