如何将OsgiBundleXmlApplicationContext设置为WebApplicationContext的父级

时间:2015-01-20 16:15:58

标签: spring apache-camel spring-ws apache-karaf spring-dm

在我的Camel(2.14.0)应用程序中,我使用Spring Web Services来触发Camel路由。该工件构建为OSGi包,并部署在Karaf(3.0.2)中。

对于第一个版本,我配置了spring-ws以通过org.springframework.remoting.support.SimpleHttpServerFactoryBean使用JVM内部Web服务器来公开Web服务。这很好用。但是不是非常OSGi-ish。所以我希望将org.springframework.ws.transport.http.MessageDispatcherServlet作为服务发布到Karaf whiteboard extender,如下所示:

<bean id="pas-ws-patient-servlet" class="org.springframework.ws.transport.http.MessageDispatcherServlet">
    <property name="contextConfigLocation" value="/endpoint-mapping.xml" /> 
</bean>

<osgi:service ref="pas-ws-patient-servlet" interface="javax.servlet.http.HttpServlet">
    <service-properties>
        <entry key="alias" value="/${pas.ws.patient.contextroot}" />
    </service-properties>
</osgi:service>

这就像“常规”servlet的魅力一​​样。但是MessageDispatcherServlet想要构建自己的WebApplicationContext并期望在该上下文中找到类型为org.springframework.ws.server.EndpointMapping的bean。 Camel提供了EndpointMapping的实现,必须与其spring-ws组件一起使用。

我面临的问题是端点映射bean的相同实例必须在创建Camel上下文的OsgiBundleXmlApplicationContext和由MessageDispatcherServlet创建的应用程序上下文之间共享。如果我的OsgiBundleXmlApplicationContextWebApplicationContext的父级,情况就是这样。虽然如何将WebApplicationContext的父上下文设置为“当前”上下文,我将servlet作为服务发布,但我不知道。

WebApplicationContext中实例化OsgiBundleXmlApplicationContext以将其传递给MessageDispatcherServlet会给我一个例外:

java.lang.IllegalArgumentException: Cannot resolve ServletContextResource without ServletContext

不幸的是,WebServiceMessageReceiver的{​​{1}}(封装了EndpointMapping)是私有成员。所以我不能直接设置映射bean。

有没有办法创建上下文层次结构?或者可以用另一种方式跨上下文共享bean实例?

1 个答案:

答案 0 :(得分:0)

解决方案实际上是直截了当的,并在FrameworkServlet的JavaDoc中进行了记录,MessageDispatcherServlet扩展了:

可以在MessageDispatcherServlet上设置ApplicationContextInitializer。使用上下文初始值设定项将当前应用程序上下文设置为servlet应用程序上下文的父级。为此,您还必须实现ApplicationContextAware接口以获取当前上下文(在这种情况下为OsgiBundleXmlApplicationContext)。然后将servlet注册为服务:

<!-- This bean sets our current context as the parent context of the XmlWebApplicationContext 
    that the MessageDispatcherServlet insists on creating. -->
<bean id="springWsContextInitializer" class="x.x.x.SpringWsContextInitializer" />

<bean id="spring-ws-servlet" class="org.springframework.ws.transport.http.MessageDispatcherServlet">
    <!-- We inherit all beans from the current context, so no need to specify a separate context file. -->
    <property name="contextConfigLocation" value="" />
    <property name="ContextInitializers" ref="springWsContextInitializer" />
</bean>

<osgi:service ref="spring-ws-servlet" interface="javax.servlet.http.HttpServlet">
    <service-properties>
        <entry key="alias" value="/${servlet.contextroot}" />
        <entry key="servlet-name" value="spring-ws-servlet" />
    </service-properties>
</osgi:service>

上下文初始化类:

public class SpringWsContextInitializer implements ApplicationContextInitializer<XmlWebApplicationContext>, ApplicationContextAware {

    private ApplicationContext applicationContext;

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

    @Override
    public void initialize(XmlWebApplicationContext applicationContext) {
        applicationContext.setParent(this.applicationContext);
    }
}

要使用 blueprint 而不是spring-dw来使用相同的东西,我必须将SpringWsContextInitializer更改为:

public class SpringWsContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    private final EndpointMapping endpointMapping;

    public SpringWsContextInitializer(final EndpointMapping endpointMapping) {
        this.endpointMapping = endpointMapping;
    }

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        StaticApplicationContext parentContext = new StaticApplicationContext();
        parentContext.refresh();
        parentContext.getDefaultListableBeanFactory().registerSingleton("endpointMapping", this.endpointMapping);
        applicationContext.setParent(parentContext);
    }
}

应该可以将端点映射bean发布为OSGi服务,然后在servlet的上下文文件中引用服务bean,但无法解析spring上下文文件所需的OSGi命名空间的OSGi命名空间处理程序