在我的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
创建的应用程序上下文之间共享。如果我的OsgiBundleXmlApplicationContext
是WebApplicationContext
的父级,情况就是这样。虽然如何将WebApplicationContext
的父上下文设置为“当前”上下文,我将servlet作为服务发布,但我不知道。
从WebApplicationContext
中实例化OsgiBundleXmlApplicationContext
以将其传递给MessageDispatcherServlet会给我一个例外:
java.lang.IllegalArgumentException: Cannot resolve ServletContextResource without ServletContext
不幸的是,WebServiceMessageReceiver
的{{1}}(封装了EndpointMapping
)是私有成员。所以我不能直接设置映射bean。
有没有办法创建上下文层次结构?或者可以用另一种方式跨上下文共享bean实例?
答案 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命名空间处理程序