vendredi 20 mars 2015

Is there a way to avoid the bottleneck in Jaxp13XPathExpression when using XPath?

I am converting a Spring managed orchestration service to use Spring Integration as a proof of concept.


I have the basic app running, but have encountered a major bottleneck.


The app uses an inbound gateway to take an XML payload from the standard MultivaluedMap:



<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>


This is then sent via a direct channel to an xpath-splitter designed to break the request (which containts many similar sub-requests) down into each actual request that can be processed.


The performance of the application was about 6 times slower than the original service, and it is due to the method org.springframework.xml.xpath.Jaxp13XPathExpressionFactory$Jaxp13XPathExpression.evaluate(Node, QName)


This is because compiled XPath expressions are not thread safe, and the method in Jaxp13XPathExpression has a synchronized block - combined with Spring using singletons... In the original service, I used a thread local containing the complied XPathExressions.


I have tried custom scopes to no avail, and this explains why


Custom Spring Scope not working for Message Channel


I have followed the example for dynamic ftp, but use the thread name as the map key. I have combined this with a child application context containing the incoming channel, the splitter and the xpath-expression, but in the code, the channel resolver gets the bean by name from the new context:


http://ift.tt/1DTA25D


I cannot do this for the XPathExpression as Jaxp13XPathExpression is a private static class within an abstract class with default access modifier.


How can I get a compiled XPathExpression with a different scope - whether it is request/session/thread, without just creating a service activator with a thread local and just not using the build in XML handling of the framework?


Further info:


Router:



<int:router input-channel="httpRequestsChannel" ref="channelResolver" method="resolve" />


Resolve Method:



public MessageChannel resolve() {
String thread = Thread.currentThread().getName();
ChannelResolverIntegrationBeans beans = this.integrationBeans
.get(thread);
if (beans == null) {
beans = createNewThreadIntegrationBeans(thread);
}
return beans.getChannel();
}


ChannelResolverIntegrationBeans method - the XPathExpression was my last attempt to get it to work, but it returns


Bean named 'dsoBatchRequestXPathNs' must be of type [javax.xml.xpath.XPathExpression], but was actually of type [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;
}


Child context beans:



<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" />

Aucun commentaire:

Enregistrer un commentaire