【问题标题】:Is there a way to avoid the bottleneck in Jaxp13XPathExpression when using XPath?使用 XPath 时有没有办法避免 Jaxp13XPathExpression 的瓶颈?
【发布时间】:2015-05-23 16:32:53
【问题描述】:

我正在转换 Spring 托管编排服务以使用 Spring Integration 作为概念证明。

我已经运行了基本应用程序,但遇到了一个主要瓶颈。

应用程序使用入站网关从标准 MultivaluedMap 获取 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 中的方法有一个同步块 - 结合 Spring 使用单例...在原始服务中,我使用了一个包含编译后的 XPathExressions 的本地线程。

我尝试了自定义范围无济于事,这解释了原因

Custom Spring Scope not working for Message Channel

我已经按照动态 ftp 的示例,但使用线程名称作为映射键。我已经将它与包含传入通道、拆分器和 xpath 表达式的子应用程序上下文相结合,但在代码中,通道解析器从新上下文中按名称获取 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 是我最后一次尝试让它工作,但它返回

名为 'dsoBatchRequestXPathNs' 的 Bean 必须是 [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 在这方面似乎表现不佳?

【问题讨论】:

    标签: java xml spring xpath spring-integration


    【解决方案1】:

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

    【讨论】:

    猜你喜欢
    • 2019-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 2011-09-13
    • 2019-02-21
    • 1970-01-01
    相关资源
    最近更新 更多