ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – Spring JUnit4手册 – /自动布线困境

2019-05-22 09:18:56  阅读:269  来源: 互联网

标签:java junit4 spring ioc-container autowired


我遇到了一个问题,这个问题只能解释为我对Spring的IoC容器设施和上下文设置缺乏了解,所以我会要求澄清一下.

仅供参考,我正在维护的应用程序具有以下堆栈技术:

> Java 1.6
>春天2.5.6
> RichFaces 3.3.1-GA UI
> Spring框架用于bean管理,Spring JDBC模块用于DAO支持
> Maven用作构建管理器
> JUnit 4.4现在作为测试引擎引入

我追溯(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());
        }
    }
}

其上下文在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...
    }
}

我在这里错过了什么?配置的哪一部分在这里有误?当我尝试通过setter手动注入bean时,测试失败,因为这部分

result = type.findAlltTypes();

在运行时被解析为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...
    }
}

或许还有其他想法吗?

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中是相同的)

标签:java,junit4,spring,ioc-container,autowired
来源: https://codeday.me/bug/20190522/1149734.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有