Apache camel 如何拆分消息对其中一条消息执行一些额外的处理并将其聚合回来

Apache camel 如何拆分消息对其中一条消息执行一些额外的处理并将其聚合回来,apache-camel,Apache Camel,我需要根据一些配置文件配置一些驼峰路由 所有配置的路由都需要将消息拆分为一个或两个子消息,然后对第一个子消息执行一些JMS集成工作,然后将JMS应答与可选的第二个消息聚合在一起。在简化的图片中,它将如下所示: message -- > split --> message 1 --> JMS request/reply --> aggregate --> more processing \--> message 2

我需要根据一些配置文件配置一些驼峰路由

所有配置的路由都需要将消息拆分为一个或两个子消息,然后对第一个子消息执行一些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(...);
所以我的问题是:

  • 我应该在树枝上放什么

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

  • 我走错路了吗。如果是的话,还有什么选择

    最初我考虑使用消息enricher,但我不想将原始消息发送到JMS

  • 我还考虑将聚合策略放在拆分器中,但我还是无法将其全部放在一起


  • 根据您的帖子,您似乎正在尝试将扩展返回与原始消息合并,但您希望向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:根据您的评论,您需要“direct:abc端点收到的原始消息可以简化很多。在本例中,我们可以使用camel现有的原始消息存储来检索传递到direct:abc的消息。如果拆分后的消息具有JmsIntegration头,我们将把正文转换为jms调用所需的格式,利用enrich语句进行jms调用,并使用自定义聚合器访问用于调用jms端点的消息、返回的消息和原始消息direct:abc has。如果您的流没有JmsIntegration头,则消息将转到路由中的Otherwise语句,该语句在结束choice语句之前不进行额外处理,然后使用您需要的任何自定义策略将spit消息聚合回一起

    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
    }
    

    根据您的帖子,您似乎正在尝试将扩展返回与原始消息合并,但您希望向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:根据您的评论,您需要“direct:abc端点收到的原始消息可以简化很多。在本例中,我们可以使用camel现有的原始消息存储来检索传递到direct:abc的消息。如果拆分后的消息具有JmsIntegration头,我们将把正文转换为jms调用所需的格式,利用enrich语句进行jms调用,并使用自定义聚合器访问用于调用jms端点的消息、返回的消息和原始消息direct:abc has。如果您的流没有JmsIntegration头,则消息将转到路由中的Otherwise语句,该语句在结束choice语句之前不进行额外处理,然后使用您需要的任何自定义策略将spit消息聚合回一起

    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
    }
    

    拆分器自动将拆分的交换重新聚合在一起。但是,默认(自2.3版起)聚合策略是返回原始exchange。通过直接在拆分器上指定默认策略,可以轻松地用自己的策略覆盖默认策略。此外,如果您没有可供选择的流,那么使用过滤器就容易得多。例如:

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

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

    拆分器会自动将拆分的交换重新聚合在一起。但是,默认(自2.3版起)聚合策略是返回原始exchange。通过直接在拆分器上指定默认策略,可以轻松地用自己的策略覆盖默认策略。此外,如果您没有可供选择的流,那么使用过滤器就容易得多。例如:

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

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

    您说过您考虑使用Enricher,但不想发送原始消息。您可以通过使用预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;
        } 
    }
    

    你说你考虑使用Enricher,但你不想发送原始信息。您可以通过使用预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;
        } 
    }
    

    我不明白这是如何解决我的问题的,在一些JMS集成之后,将第一个拆分的消息与第二个完全没有处理的拆分消息放在一起。在您的示例中,moth split消息由同一个MyOrderService bean处理,这与我的完全不同case@Julian,为了更清晰,我已经更新了示例,以使用您的原始代码。此外,我还添加了使用过滤器的建议,这可能是您正在寻找的主要内容