有没有办法在使用XPath时避免Jaxp13XPathExpression的瓶颈?

时间:2015-03-20 09:46:46

标签: java xml spring xpath spring-integration

我正在转换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(&quot;XML&quot;)"> 
</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:

https://github.com/spring-projects/spring-integration-samples/blob/master/advanced/dynamic-ftp/src/main/java/org/springframework/integration/samples/ftp/DynamicFtpChannelResolver.java

我无法为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在这方面看起来并不高效?

1 个答案:

答案 0 :(得分:1)

JAXP XPathExpression不仅非线程安全,而且我猜您可能正在使用它来访问DOM,这也不是线程安全的。考虑切换到Saxon,其中编译的XPath表达式和本机树模型都是线程安全的,作为奖励,您可以访问XPath 2.0。