Java 将ApplicationContext创建为Springbean(通过其他应用程序上下文)

Java 将ApplicationContext创建为Springbean(通过其他应用程序上下文),java,spring,Java,Spring,如何在其他应用程序上下文中将一个ApplicationContext定义为原型Springbean。我还需要将当前上下文作为父上下文传递给新的应用程序上下文 详情: 我有Bean,它表示富客户机应用程序中的单用户会话。这个类管理应用程序上下文的生存期,以及很少的其他对象(如数据库连接)。此会话bean本身由特殊的“启动应用程序上下文”配置 现在我想对这个会话bean进行单元测试,但遇到了麻烦,因为会话bean内部创建了特定于会话的应用程序上下文,并且有许多依赖于“启动上下文” 示例代码: pub

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

详情:

我有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);
    }
}
出于测试目的,我希望Recurse createSessionContext函数代码如下所示:

sessionContext = startupContext.getBean("adminContext", ApplicationContext.class);
然后我可以创建startupContext的模拟,返回一些存根。甚至在将来,通过spring将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>

admin-session.xml
我还考虑在顶层创建应用程序上下文并通过setter传递,但是:

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

    看起来很愚蠢的是,我无法从IoC框架本身获取IoC对象。可能是我误读了一些spring文档


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

    如果我理解正确,您的需求是在手动控制的范围内管理bean集合(在本例中是您的RIA会话)

    Spring支持。您有基本的
    singleton
    prototype
    范围,webapps也有
    请求
    会话
    范围。如果您的RIA会话实际上是HTTP会话,那么我建议您使用而不是手动嵌套的应用程序上下文设计

    如果您的会话与web无关,那么您仍然可以选择定义自己的会话。这方面还有更多的工作要做,但它是容器中定义的扩展点,所以您处于安全地带


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

    使用
    FactoryBean
    ApplicationContextAware
    接口

    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>
    
    
    applicationContext.xml
    
    这不是web应用程序。我知道范围bean,但在这种情况下是不可接受的。每个子应用程序上下文都非常不同,甚至不是所有的jar文件都可以在用户安装时出现。我也不需要单件的工厂定位器。例如:用户执行一些数据库管理任务,并希望看到更改。然后我必须删除DB管理上下文,并启动常规用户上下文。父上下文也很重要,必须在创建子上下文之前进行配置(例如,我需要注入会话引用)。但我尝试在注销时重新启动完整的应用程序。