如何拆分消息对其中一个进行一些额外的处理并将它们聚合回来

时间:2016-05-11 03:39:56

标签: apache-camel

我需要根据一些配置文件配置一些camel路由。

所有已配置的路由都需要将消息拆分为一个或两个子消息,然后在第一个消息上执行一些JMS集成工作,然后将JMS应答与可选的第二个消息聚合在一起。在简化的图片中,它将如下所示:

message -- > split  --> message 1 --> JMS request/reply --> aggregate --> more processing
                   \--> message 2                      / 

聚合将在完成大小上完成,如果它将是1或2,我可以提前知道,具体取决于路由元数据。当第二条消息出现时,在与JMS回复合并之前不需要其他处理。

简而言之,我需要拆分,然后是路由,然后是聚合,这是一种非常常见的模式。唯一的特点是,如果第二个拆分消息存在,我不需要在聚合之前对其进行任何操作。

在java DSL中,它看起来像这样:

from("direct:abc")
    // The splitter below  will set the JmsIntegration flag
    .split().method(MySplitter.class, "split")
    .choice()
        .when(header("JmsIntegration"))
            .inOut("jms:someQueue"))
        .otherwise()
            // what should I have on here?
            .to(???)
    .end()
    .aggregate(...)to(...);

所以我的问题是:

  1. 我应该在其他分支上放什么?

    我需要的是if:如果拆分消息需要JMS转到JMS,然后转移到聚合器,如果它不直接转到聚合器。我正在考虑创建一个虚拟处理器,它实际上什么都不做,但这在我看来是一种天真的方法。

  2. 我走错了路。如果是这样,那将是另类

    最初我正在考虑加强消息,但我不想将原始消息发送给JMS

  3. 我还考虑将我的聚合策略放在我的分配器中,但我再也无法将它们放在一起。

3 个答案:

答案 0 :(得分:1)

根据您的帖子,您似乎试图将原始消息的富集合并返回,但您希望将自定义消息发送到jms端点。我建议将原始邮件存储在bean或缓存中或类似的东西中,利用camel的所有转换,然后让聚合策略利用存储来返回所需的格式。

from("direct:abc")
    .split().method(MySplitter.class, "split")
        .choice()
            .when(header("JmsIntegration"))
                .beanRef("MyStorageBean", "storeOriginal")
                .convertBodyTo(MyJmsFormat.class)
                //This aggregation strategy could have a reference 
                //to your storage bean and retrieve the instance
                .enrich("jms:someQueue", myCustomAggreationStrategyInstance)
            .otherwise()
         .end()
    .aggregate(...)
    .to("direct:continueProcessing");

选项#2:基于你的评论说你需要"原始消息,直接:abc端点收到这个可以简化很多。在这个例子中,我们可以使用camel现有的原始消息存储来检索传递给direct:abc的消息。如果您在拆分后的消息有一个JmsIntegration标头,我们会将主体转换为所需的jms调用格式,利用enrich语句进行jms调用,并使用自定义聚合器,使您可以访问用于调用jms端点的消息,回来的消息和原始消息直接:abc有。如果您的流没有JmsIntegration标头,则消息将转到您的路由中的OTHER语句,该语句在结束选择语句之前不进行其他处理,然后将吐出的消息与您需要的任何自定义策略一起聚合在一起。

from("direct:abc")
    .split().method(MySplitter.class, "split")
        .choice()
            .when(header("JmsIntegration"))
                .convertBodyTo(MyJmsFormat.class)
                //See aggregationStrategy sample below
                .enrich("jms:someQueue", myAggStrat)
            .otherwise()
                //Non JmsIntegration header messages come here, 
                //but receive no work and are passed on.
         .end()
    .aggregate(...)
    .to("direct:continueProcessing");

//Your Custom Aggregator
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
    //This logic will retrieve the original message passed into direct:abc
    Message originalMessage =(Message)exchange.getUnitOfWork().getOriginalInMessage();
    //TODO logic for manipulating your exchanges and returning the desired result
}

答案 1 :(得分:0)

你说你考虑过使用Enricher,但是你不想发送原始信息。您可以使用pre-JMS路由来巧妙地解决这个问题:

from("direct:abc")
    .enrich("direct:sendToJms", new MyAggregation());
    .to("direct:continue");

from("direct:sendToJms")
    // do marshalling or conversion here as necessary
    .convertBodyTo(MyJmsRequest.class)
    .to("jms:someQueue");

public class MyAggregation implements AggregationStrategy {

    public Exchange aggregate(Exchange original, Exchange resource) {
        MyBody originalBody = original.getIn().getBody(MyBody.class);
        MyJmsResponse resourceResponse = resource.getIn().getBody(MyJmsResponse.class);
        Object mergeResult = ... // combine original body and resource response
        original.getIn().setBody(mergeResult);
        return original;
    } 
}

答案 2 :(得分:-1)

Splitter会自动将拆分交换聚合在一起。但是,默认(自2.3)聚合策略是返回原始交换。您可以通过直接在Splitter上指定默认策略来轻松覆盖默认策略。此外,如果您的选择没有替代流程,那么使用Filter会更容易。例如:

from("direct:abc")
    .split().method(MySplitter.class, "split").aggregationStrategy(new MyStrategy())
        .filter(header("JmsIntegration"))
            .inOut("jms:someQueue"))
        .end()
    .end()
    .to(...);

您仍然需要实施MyStrategy来合并这两条消息。