Есть ли способ избежать узкого места в Jaxp13XPathExpression при использовании XPath?

1

Я преобразовываю службу управляемой оркестровки Spring, чтобы использовать Spring Integration в качестве доказательства концепции.

У меня есть основное приложение работает, но столкнулись с основным узким местом.

Приложение использует входящий шлюз для получения полезной нагрузки XML из стандартной 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>

Затем он отправляется по прямому каналу в расщепитель xpath, предназначенный для прерывания запроса (который содержит множество подобных подзадач) вниз в каждый фактический запрос, который может быть обработан.

Производительность приложения примерно в 6 раз медленнее, чем исходная услуга, и это связано с методом org.springframework.xml.xpath.Jaxp13XPathExpressionFactory $ Jaxp13XPathExpression.evaluate(Node, QName)

Это связано с тем, что скомпилированные выражения XPath не являются потокобезопасными, а метод в Jaxp13XPathExpression имеет синхронизированный блок - в сочетании с Spring с использованием синглтонов... В исходной службе я использовал локальный поток, содержащий выполненные XPathExressions.

Я пробовал пользовательские области безрезультатно, и это объясняет, почему

Пользовательский весовой диапазон не работает для канала сообщений

Я последовал примеру динамического ftp, но использую имя потока в качестве ключа карты. Я объединил это с контентом дочернего приложения, содержащим входящий канал, разделитель и выражение xpath, но в коде распознаватель канала получает бит по имени из нового контекста:

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' должен иметь тип [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;
}

Контейнеры для дочернего контекста:

<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

Я выяснил, что все компоненты в дочернем контексте на самом деле различны для каждого канала, проверяя их хэш-коды. Все, что требовалось, - это создать дочерний контекст и динамически маршрутизировать на входящий канал.

На самом деле это не помогло решить проблемы с производительностью - это примерно вдвое медленнее, чем исходная услуга. Весенняя интеграция просто не кажется успешной в этой области, если я что-то не хватает?

Теги:
spring
xpath
spring-integration

1 ответ

1

JAXP XPathExpression не является потокобезопасным, но я думаю, вы, вероятно, используете его для доступа к DOM, который также не является потокобезопасным. Рассмотрим переход на Saxon, где и скомпилированное выражение XPath, и собственная древовидная модель являются потокобезопасными, а в качестве бонуса вы получаете доступ к XPath 2.0.

  • 0
    Кроме того, см. Ответ на этот вопрос stackoverflow.com/questions/26496211/… , как включить Saxon без манипуляций с кодом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню