我正在转换Spring托管业务流程服务,以使用Spring Integration作为概念证明。
我已经运行了基本的应用程序,但遇到了一个主要的瓶颈。
该应用程序使用入站网关从标准多值地图中获取XML有效负载:
<int-http:inbound-gateway id="DSOWebServicePOC" request-channel="httpRequestsChannel"
reply-channel="httpResponsesChannel" path="/orchestrate/do" supported-methods="POST"
payload-expression="#requestParams.getFirst("XML")">
</int-http:inbound-gateway>
然后通过直接通道将其发送到xpath-splitter,用于将请求(包含许多类似的子请求)分解为可以处理的每个实际请求。
应用程序的性能比原始服务慢约6倍,这是由于方法org.springframework.xml.xpath.Jaxp13XPathExpressionFactory $ Jaxp13XPathExpression.evaluate(Node,QName)
这是因为编译的XPath表达式不是线程安全的,并且Jaxp13XPathExpression中的方法有一个synchronized块 - 与使用单例的Spring结合...在原始服务中,我使用了一个包含已编译的XPathExressions的本地线程。
我尝试过自定义范围无济于事,这就解释了为什么
Custom Spring Scope not working for Message Channel
我已经按照动态ftp的示例,但使用线程名称作为映射键。我将它与包含传入通道,拆分器和xpath-expression的子应用程序上下文相结合,但在代码中,通道解析器从新上下文中按名称获取bean:
我无法为XPathExpression执行此操作,因为Jaxp13XPathExpression是具有默认访问修饰符的抽象类中的私有静态类。
如何获得具有不同作用域的已编译XPathExpression - 无论是请求/会话/线程,还是仅使用本地线程创建服务激活器而不使用框架的XML处理构建?
更多信息:
路由器:
<int:router input-channel="httpRequestsChannel" ref="channelResolver" method="resolve" />
解决方法:
public MessageChannel resolve() {
String thread = Thread.currentThread().getName();
ChannelResolverIntegrationBeans beans = this.integrationBeans
.get(thread);
if (beans == null) {
beans = createNewThreadIntegrationBeans(thread);
}
return beans.getChannel();
}
ChannelResolverIntegrationBeans方法 - XPathExpression是我最后一次尝试让它工作,但它返回
Bean命名为&#39; dsoBatchRequestXPathNs&#39;必须是[javax.xml.xpath.XPathExpression]类型,但实际上是[org.springframework.xml.xpath.Jaxp13XPathExpressionFactory $ Jaxp13XPathExpression]类型
private synchronized ChannelResolverIntegrationBeans createNewThreadIntegrationBeans(
String thread) {
ChannelResolverIntegrationBeans beans = this.integrationBeans
.get(thread);
if (beans == null) {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] { "/xmlChildHandlerContext.xml" }, this.appContext);
MessageChannel channel = ctx.getBean("fromDynamicRouter",
MessageChannel.class);
EventDrivenConsumer splitter = ctx.getBean("requestSplitter",
EventDrivenConsumer.class);
XPathExpression expression = ctx.getBean("dsoBatchRequestXPathNs",
XPathExpression.class);
beans = new ChannelResolverIntegrationBeans(channel, splitter);
this.integrationBeans.put(thread, beans);
// Will works as the same reference is presented always
this.contexts.put(beans, ctx);
}
return beans;
}
子上下文bean:
<int:channel id="fromDynamicRouter" />
<int-xml:xpath-splitter id="requestSplitter"
input-channel="fromDynamicRouter" output-channel="xPathSplitterResultsChannel"
xpath-expression-ref="dsoBatchRequestXPathNs">
</int-xml:xpath-splitter>
<int-xml:xpath-expression id="dsoBatchRequestXPathNs"
expression="/dso:DsoRequests/dso:DsoRequest/*" namespace-map="namespaceMap" />
UDPATE
通过检查它们的哈希码,我发现子上下文中的所有bean实际上每个通道都不同。所需要的只是创建子上下文并动态路由到传入通道。
这并没有真正解决性能问题 - 它仍然是原始服务的两倍慢。除非我遗漏了什么东西,否则Spring Integration在这方面看起来并不高效?
答案 0 :(得分:1)
JAXP XPathExpression不仅非线程安全,而且我猜您可能正在使用它来访问DOM,这也不是线程安全的。考虑切换到Saxon,其中编译的XPath表达式和本机树模型都是线程安全的,作为奖励,您可以访问XPath 2.0。