Spring integration 级联聚合器不返回消息

Spring integration 级联聚合器不返回消息,spring-integration,Spring Integration,我正在使用spring集成从外部系统并发地(使用taskmanager)拉入不同的帐户详细信息,并将其聚合到一个帐户对象中。为此,我必须对消息进行两级拆分,在获取消息之后,需要在两级进行聚合。我使用简单的POJO实现拆分器、路由器和聚合器。我正在实施相关策略,使用一个简单的消息组,但没有实施任何发布策略。由于某种原因,我的邮件在第二个聚合器中丢失了。调试时,我可以看到来自第一级聚合器的消息进入第二级聚合器,但它无法将这些消息传递到输出通道 还有一个观察结果是,如果只有一条消息,我将得到输出。但是

我正在使用spring集成从外部系统并发地(使用taskmanager)拉入不同的帐户详细信息,并将其聚合到一个帐户对象中。为此,我必须对消息进行两级拆分,在获取消息之后,需要在两级进行聚合。我使用简单的POJO实现拆分器、路由器和聚合器。我正在实施相关策略,使用一个简单的消息组,但没有实施任何发布策略。由于某种原因,我的邮件在第二个聚合器中丢失了。调试时,我可以看到来自第一级聚合器的消息进入第二级聚合器,但它无法将这些消息传递到输出通道

还有一个观察结果是,如果只有一条消息,我将得到输出。但是在任何导致多条消息聚合的情况下,我看不到任何输出,线程被挂起

谢谢你的帮助

以下是上下文定义

    <bean id="accountManager" class="<package>.AccountManager"/>

<int:gateway id="accountBuilder"
    service-interface="<package>.AccountBuilder" default-request-channel="accountRequest"  default-reply-channel="allAccounts"/>

<int:channel id="accountRequest"/>
<int:channel id="allAccounts"/>
<int:splitter input-channel="accountRequest" output-channel="accountRequests" ref="accountSplitter" method="split"/>

<int:channel id="accountRequests">
    <int:dispatcher task-executor="accountServiceTaskExecutor"/>
</int:channel>

<int:router input-channel="accountRequests" ref="accountRouter" method="routeAccountRequests">
    <int:mapping channel="retailRequest"/>
    <int:mapping channel="manualRequest"/>
</int:router>

<bean id="accountMessageStore" class="org.springframework.integration.store.SimpleMessageStore" />

<bean id="searchResultMessageStoreReaper" class="org.springframework.integration.store.MessageGroupStoreReaper">
    <property name="messageGroupStore" ref="accountMessageStore" />
    <property name="timeout" value="2000" />
</bean>

<!-- **************************************************************************** -->
<!-- **************************** RETAIL ACCOUNTS ******************************* -->
<!-- **************************************************************************** -->

<int:channel id="retailRequest"/>

<int:splitter input-channel="retailRequest" output-channel="retailAccountRequests" ref="retailAccountSplitter" method="split"/>

<int:channel id="retailAccountRequests">
    <int:dispatcher task-executor="accountServiceTaskExecutor"/>
</int:channel>

<int:router input-channel="retailAccountRequests" ref="retailAccountRouter" method="routeRetailAccountRequests">
    <int:mapping channel="retailAccountDataRequest"/>
    <int:mapping channel="retailAccountDetailsRequest"/>
    <int:mapping channel="retailAccountPositionsRequest"/>
</int:router>

<int:channel id="retailAccountDataRequest"/>
<int:service-activator input-channel="retailAccountDataRequest" ref="retailAccountDataMapper"
                       method="getRetailAccountData" output-channel="aggregatedRetailAccounts"/>

<int:channel id="retailAccountDetailsRequest"/>
<int:service-activator input-channel="retailAccountDetailsRequest" ref="retailAccountDetailsMapper"
                       method="getRetailAccountDetails" output-channel="aggregatedRetailAccounts"/>

<int:channel id="retailAccountPositionsRequest"/>
<int:service-activator input-channel="retailAccountPositionsRequest" ref="retailAccountPositionsMapper"
                       method="getRetailAccountPositions" output-channel="aggregatedRetailAccounts"/>

<int:channel id="aggregatedRetailAccounts" />
<int:aggregator input-channel="aggregatedRetailAccounts"
    ref="retailAccountAggregator" method="aggregate" output-channel="aggregatedAccounts"
    message-store="accountMessageStore" expire-groups-upon-completion="true"/>

<!-- ************************** END RETAIL ACCOUNTS ***************************** -->

<!-- **************************************************************************** -->
<!-- **************************** MANUAL ACCOUNTS ******************************* -->
<!-- **************************************************************************** -->

<int:channel id="manualRequest"/>

<int:splitter input-channel="manualRequest" output-channel="manualAccountRequests" ref="manualAccountSplitter" method="split"/>

<int:channel id="manualAccountRequests">
    <int:dispatcher task-executor="accountServiceTaskExecutor"/>
</int:channel>

<int:router input-channel="manualAccountRequests" ref="manualAccountRouter" method="routeManualAccountRequests">
    <int:mapping channel="manualAccountDataRequest"/>
    <int:mapping channel="manualAccountDetailsRequest"/>
    <int:mapping channel="manualAccountPositionsRequest"/>
</int:router>

<int:channel id="manualAccountDataRequest"/>
<int:service-activator input-channel="manualAccountDataRequest" ref="manualAccountDataMapper"
                       method="getManualAccountData" output-channel="aggregatedManualAccounts"/>

<int:channel id="manualAccountDetailsRequest"/>
<int:service-activator input-channel="manualAccountDetailsRequest" ref="manualAccountDetailsMapper"
                       method="getManualAccountDetails" output-channel="aggregatedManualAccounts"/>

<int:channel id="manualAccountPositionsRequest"/>
<int:service-activator input-channel="manualAccountPositionsRequest" ref="manualAccountPositionsMapper"
                       method="getManualAccountPositions" output-channel="aggregatedManualAccounts"/>

<int:channel id="aggregatedManualAccounts"/>
<int:aggregator input-channel="aggregatedManualAccounts"
ref="manualAccountAggregator" method="aggregate" output-channel="aggregatedAccounts"
message-store="accountMessageStore" expire-groups-upon-completion="true"/>

<!-- ************************** END MANUAL ACCOUNTS ***************************** -->

<int:channel id="aggregatedAccounts" />
<int:aggregator input-channel="aggregatedAccounts" ref="accountAggregator"
    method="aggregate" output-channel="allAccounts" message-store="accountMessageStore"
    expire-groups-upon-completion="true" />




<bean id="accountServiceTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="25" />
    <property name="maxPoolSize" value="250" />
    <property name="queueCapacity" value="500" />
</bean>

使用标准相关头(
correlationId
)时,嵌套序列细节(
correlationId
sequenceSize
sequenceNumber
)由框架自动维护在堆栈中,该堆栈被推送(在后续拆分器中)并弹出(在聚合器中)在标题下
sequenceDetails
。请参阅下面相应的
popSequenceDetails()

如果您使用的是非标准相关性,那么在嵌套拆分器时,您有责任以类似的方式保持其笔直

如果希望框架处理嵌套拆分,只要将数据存储在
correlationId
头中,非标准相关性就不是问题

与往常一样,调试日志记录和通过流跟踪消息通常会识别这些类型的问题


PS:始终尝试指示您正在使用的版本。

欢迎使用堆栈溢出!如果在这个问题中包含一些经过提炼的示例代码,这样我们就可以重现这个问题,那么您就更有可能得到有用的答案。请参阅以获取更多建议。嗨,Gary,谢谢您的回复。我在两个级别的聚合器中都使用了关联策略。但是,我只使用自定义CorrelationID来跟踪消息。releaseStrategy是否是跟踪自定义sequenceSize和sequenceNumber的正确位置?你能给我指出一个示例代码吗?再次感谢!我使用的是spring integration的4.0.0.M2版本。处理这个问题最简单的方法可能是在第二个拆分器之前添加一个
,以在其他标头中保存以前聚合器的标头。然后在“内部”聚合器之后使用另一个聚合器来恢复外部聚合器的头。但是请记住,您不能将自定义的
sequence*
头与默认的
SequenceSizeReleaseStrategy
一起使用;它使用标准标题。Gary,谢谢!你的建议奏效了。我正在从外部聚合器返回消息。但是,在收到消息后,任务执行器生成的线程仍在无限期运行。我使用“org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor”在两个级别上为路由器提供多线程。这是因为您的
核心池大小为25。超过核心池大小的线程将在经过
keepaliveSeconds
(默认值60)后终止。