spring integration - splitter and aggregator

时间:2016-02-18 19:09:53

标签: spring-integration

目前我正在为新应用程序使用spring集成,并开始知道如何处理故障情况。 在我的应用程序中,spring集成将从IBM mq接收消息并验证头信息并根据消息类型路由到不同的队列。传入的消息可能是批量消息,所以我使用了Spring集成的分离器和聚合器,并且在技术工作流程方面取得了很好的进展和控制。 目前我们面临的问题很少,我们将IBM mq和webservice作为我们的网关。两个网关都接收消息并发送到分离器信道,其中分离器分割消息并发送到出站信道(执行器信道)。所以消息将并行发送到目的地,状态更新服务激活器将接收具有order = 2的相同信道的消息并发送给聚合器。所以它的实施很好。

问题: 如果jms出站网关抛出execption我已经添加了advise作为异常处理程序,它将发送给另一个服务激活器以将故障状态更新为DTO对象并且将具有与输出相同的聚合器通道但是在这种情况下我没有在聚合器通道中接收消息聚合器只能在愉快的流程中接收。

我想聚合出站成功消息和失败消息(其他服务激活器更新状态),然后完成状态需要作为另一个出站或web服务中的响应发布到响应队列。

我试图命令成功的服务激活器和故障错误处理程序服务激活器具有相同的通道,这是聚合器的输入通道并且它不起作用。

感谢您对继续此工作流程的指导

使用Spring Integration 2.2.2

<channel id="inbound"/>
<channel id="splitterInChannel"/>

<channel id="splitterOutChannel">
<dispatcher task-executor="splitterExecutor"/>
</channel>          
<beans:bean id="splitterExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <beans:property name="corePoolSize" value="5" />
    <beans:property name="maxPoolSize" value="10" />
    <beans:property name="queueCapacity" value="25" />
</beans:bean>
<channel id="ValidatorChannel"/>

<channel id="outBoundjmsChannel"/>
<channel id="outBoundErrorChannel"/>
<channel id="finalOutputChannel"></channel>
<channel id="aggregatorChannel"/>

<jms:inbound-channel-adapter connection-factory="AMQConnectionFactory" 
destination="AMQueue" channel="inbound" auto-startup="true" 
extract-payload="false" acknowledge="transacted"></jms:inbound-channel-adapter>


<service-activator ref="InBoundProcessor" input-channel="inbound" output-channel="splitterInChannel"></service-activator>

<!-- splitter -->
<splitter ref="Splitter" method="splitInput" input-channel="splitterInChannel" output-channel="splitterOutChannel"/>
<!-- validator -->
<service-activator ref="Validator" method="validate" input-channel="splitterOutChannel" output-channel="ValidatorChannel"/>         

<!-- need to add enricher -->
<service-activator ref="Enricher" method="enrich" input-channel="ValidatorChannel" output-channel="outBoundjmsChannel"/>            

<!-- outbound gateway -->

<jms:outbound-channel-adapter channel="outBoundjmsChannel" connection-factory="AMQConnectionFactory" destination-name="outputQueue" 
message-converter="customMessageConvertor" order="1"  >

        <jms:request-handler-advice-chain>
            <beans:bean class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
                <beans:property name="retryTemplate" >
                    <beans:bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
                        <beans:property name="retryPolicy">
                            <beans:bean class="org.springframework.retry.policy.SimpleRetryPolicy">
                            <beans:property name="maxAttempts" value="2" />
                            </beans:bean>
                        </beans:property>
                    <beans:property name="backOffPolicy">
                        <beans:bean class="org.springframework.retry.backoff.FixedBackOffPolicy">
                        <beans:property name="backOffPeriod" value="1000" />
                        </beans:bean>
                        </beans:property>
                    </beans:bean>            
                </beans:property>
                <beans:property name="recoveryCallback">
                    <beans:bean class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
                        <beans:constructor-arg ref="outBoundErrorChannel" />
                    </beans:bean>
                </beans:property>

            </beans:bean>
        </jms:request-handler-advice-chain>
    </jms:outbound-channel-adapter>



<!-- outBound error processor -->           
<service-activator  ref="ErrorProcessor" method="errorHandling" input-channel="outBoundErrorChannel" output-channel="aggregatorChannel" />          
<!-- Post send processor -->
<service-activator  ref="PostProcessor" method="Postprocessing" input-channel="outBoundjmsChannel" output-channel="aggregatorChannel" order="2"/>           
<!-- aggregator -->
<aggregator ref="Aggregator" correlation-strategy-method="aggregateStrategy" input-channel="aggregatorChannel" output-channel="finalOutputChannel"
release-strategy-method="isRelease" method="aggregate" expire-groups-upon-completion="true"/>


<!-- final processor or responder -->
<service-activator ref="FinalProcessor" method="endProcessing" input-channel="finalOutputChannel"/>         

</beans:beans>

在上面的配置中,我已经将发布策略称为false,并将相关方法作为空字符串,如果这有效,我将为批处理生成UUID,并将UUID附加到拆分器中以进行解析。

在调试上述配置时,我注意到出站错误通道在尝试发送到出站适配器时接收(在我的情况下,它发送两次)。我不想在其中一个应用程序和另一个应用程序中重新尝试重新发布消息。 在这两种情况下,我想在最后一次聚合尝试后将消息发送到出站错误通道,如果失败,我将在ErrorProcessor中将状态更新为无法发送。

两个问题。 1.我收到重复的信息到频道,很难确定最后的失败或成功。 2.不能为发布策略制定逻辑,难以识别哪个是重复,是否成功。

在上面的例子中,我找不到比较对象的通用方法,因为equals方法没有适当的属性来比较,它不会 正确的方法与布尔字段进行比较。

请帮我解决此问题以继续我的工作流程设计和完成。

非常感谢指导我继续。 谢谢, 克里希S

目前

public Object errorHandling(Object object){
        OutBoundMessage outBoundMessage = null;
        if(object instanceof MessagingException){

            outBoundMessage =((MessagingException) object).getFailedMessage();
        }else{
            //TODO: log the message
        }

        return outBoundMessage;
    }




    public String aggregateStrategy(OutBoundMessage outBoundMessage){

        //TODO: get the UUID from outbound message and return 
        return "";
    }




public List<OutBoundMessage> splitter(InBoundMessage inBoundMessage){

        String[] message = inBoundMessage.getRawMessage().split(",");
        long uuid = java.util.UUID.randomUUID().getLeastSignificantBits();
        List<OutBoundMessage> outBoundMessagelist = new ArrayList<OutBoundMessage>();
        for (String string : message) {
            OutBoundMessage outBoundMessage = new outBoundMessage();
            outBoundMessage.setCorrelationID(uuid);
            outBoundMessagelist.add(outBoundMessage);
        }

    }

在以下方法中添加为默认值false以验证

public boolean isRelease(List<OutBoundMessage> outBoundMessage){
        //TODO: need to define condition for closing the list aggregation
        return false;
    }

2 个答案:

答案 0 :(得分:2)

请分享您的correlation-strategy-method="aggregateStrategy"源代码。还有ErrorMessage

我想知道您在correlationKey之后如何处理ErrorProcessor以及如何从邮件中恢复correlationKey

不确定如何构建自己的<splitter>,但applySequence = true默认提供Correlation Details。因此,每个拆分邮件中都可以使用ErrorMessage以便以后进行聚合。

对于ErrorMessageSendingRecoverer中的Exception,我建议您注意那里的payload ErrorMessageSendingRecoverer。它看起来像(来自else if (!(lastThrowable instanceof MessagingException)) { lastThrowable = new MessagingException((Message<?>) context.getAttribute("message"), lastThrowable.getMessage(), lastThrowable); } .... messagingTemplate.send(new ErrorMessage(lastThrowable)); 源代码):

MessagingException

因此,Correlation Details对于Exception有一条“有罪”的消息,而且该消息对于聚合器具有适当的Add Missing Constraints标头。因此,如果您想将错误聚合到同一个消息组,则应该依赖它们。

答案 1 :(得分:0)

最后,我了解它是如何运作的,

我在消息转换器中将布尔值设置为true,并在Errorhandle中将其设置为false并返回null,因此恢复是将消息作为失败消息接收到聚合器并了解当我返回对象时会发生什么 感谢@ArtemBilan,您的代码块让我了解了发生了什么以及我该怎么做