创建ApplicationContext作为Spring bean(通过其他应用程序上下文)

时间:2010-07-21 20:47:13

标签: java spring

如何在其他应用程序上下文中将一个ApplicationContext定义为原型spring bean。此外,我需要将当前上下文作为父项传递给新的应用程序上下文。

详细说明:

我有Bean,代表富客户端应用程序中的一个用户会话。此类管理应用程序上下文的生命周期,以及其他一些对象(如数据库连接)。此会话bean本身由特殊的“启动应用程序上下文”配置。

现在我想要对这个会话bean进行单元测试,但由于在会话bean中创建了会话特定的应用程序上下文,并且有许多依赖于“启动上下文”,因此会出现问题;

示例代码:

public class UserDBAminSession implements ApplicationContextAware, UserSession {
    ApplicationContext startupContext;
    ApplicationContext sessionContext;

    public void setApplicationContext(ApplicationContext startupContext) {...}

    public void start() {
        createSessionContext() ;
    }

    private void createSessionContext() {
        sessionContext = new ClassPathXmlApplicationContext("admin-session.xml", startupContext);
    }
}

出于测试目的,我希望使用以下内容复制createSessionContext函数代码:

sessionContext = startupContext.getBean("adminContext", ApplicationContext.class);

然后我可以创建startupContext的模拟,返回一些存根。或者甚至DI“会话上下文”到春天的bean,在某个未来。但是,我不知道如何将父上下文参数传递给ClassPathXmlApplicationContext构造函数。我尝试这样的东西,但似乎不起作用:

<bean id="adminContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"
        scope="prototype" autowire="constructor">
    <constructor-arg type="java.lang.String">
        <value>admin-session.xml</value>
    </constructor-arg>
</bean>

此外,我考虑在顶级创建应用程序上下文并通过setter传递它,但是:

  1. 这只是将问题移到上一级,而不是解决。事实上它已经完成了(UserSession - 这是“顶级”)。
  2. 这破坏了RAII模式。
  3. 这需要大量的代码重构。
  4. 或者制作特殊的“上下文工厂”对象,但它已经不是最好的代码了。

    什么看起来很愚蠢,我不能从IoC框架本身的IoC对象。可能是我误读了一些弹簧文档?

    还有其他想法,如何对这个班级进行单元测试?

2 个答案:

答案 0 :(得分:3)

使用FactoryBeanApplicationContextAware接口。

public class ChildApplicationContextFactoryBean implements FactoryBean, ApplicationContextAware {

    protected String[] configLocations;

    protected ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object getObject() throws Exception {
        return new ClassPathXmlApplicationContext(configLocations, applicationContext);
    }

    @Override
    public Class getObjectType() {
        return ClassPathXmlApplicationContext.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public void setConfigLocations(String[] configLocations) {
        this.configLocations = configLocations;
    }

}

用法:

<bean class="com.skg.ecg.portal.operation.transit.ChildApplicationContextFactoryBean">
    <property name="configLocations">
        <list>
            <value>applicationContext.xml</value>
        </list>
    </property>
</bean>

答案 1 :(得分:0)

如果我理解正确,您的要求是在手动控制的范围内管理一组bean(在本例中为RIA会话)。

Spring支持scoped beans。您拥有基本的singletonprototype范围,并且网络广告也会获得requestsession范围。如果您的RIA会话实际上是一个HTTP会话,那么我建议您使用session-scoped beans而不是手动嵌套的应用程序上下文设计。

如果您的会话与网络无关,那么您仍然可以选择自定义custom scope。在这方面还有更多的工作,但它是容器中定义的扩展点,因此您处于安全的地方。

你最初认为应用程序上下文本身就是父上下文中的bean会起作用,是的,但在这种情况下它可能是不必要的,只会增加复杂性。但是,如果要进一步调查它,请查看SingletonBeanFactoryLocator,它是用于管理应用程序上下文层次结构的Spring基础结构类。它不会做你想要的具体工作,但它可能会给你一些想法。