Java 配置Spring集成聚合器以组合来自RabbitMq扇出交换的响应

Java 配置Spring集成聚合器以组合来自RabbitMq扇出交换的响应,java,rabbitmq,spring-integration,spring-amqp,Java,Rabbitmq,Spring Integration,Spring Amqp,我正在尝试使用Spring集成配置以下内容: 向频道发送消息 将此消息发布到具有n个消费者的rabbit fanout(发布/订阅)交易所 每个使用者都提供一条响应消息 让Spring Integration在将这些响应返回到原始客户端之前聚合这些响应 到目前为止,我对此有一些问题 我使用发布-订阅频道来设置apply sequence=“true”属性,以便设置correlationId、sequenceSize和sequenceNumber属性。这些属性正被DefaultAmqpHeader

我正在尝试使用Spring集成配置以下内容:

  • 向频道发送消息
  • 将此消息发布到具有n个消费者的rabbit fanout(发布/订阅)交易所
  • 每个使用者都提供一条响应消息
  • 让Spring Integration在将这些响应返回到原始客户端之前聚合这些响应
  • 到目前为止,我对此有一些问题

  • 我使用发布-订阅频道来设置
    apply sequence=“true”
    属性,以便设置correlationId、sequenceSize和sequenceNumber属性。这些属性正被
    DefaultAmqpHeaderMapper
    丢弃<代码>调试头名称=[correlationId]将不会被映射

  • sequenceSize属性仅设置为1,即使在fanout exchange中注册了2个队列。这可能意味着聚合器过早地发布消息。我认为这是因为我滥用发布-订阅频道来使用
    apply-sequence=“true”
    ,并且说只有一个订阅者是非常正确的,即
    int-amqp:outbound-gateway

  • 我的出站Spring配置如下:

    <int:publish-subscribe-channel id="output" apply-sequence="true"/>
    
    <int:channel id="reply">
        <int:interceptors>
            <int:wire-tap channel="logger"/>
        </int:interceptors>
    </int:channel>
    
    <int:aggregator input-channel="reply" method="combine">
        <bean class="example.SimpleAggregator"/>
    </int:aggregator>
    
    <int:logging-channel-adapter id="logger" level="INFO"/>
    
    <int:gateway id="senderGateway" service-interface="example.SenderGateway" default-request-channel="output" default-reply-channel="reply"/>
    
    <int-amqp:outbound-gateway request-channel="output"
                                       amqp-template="amqpTemplate" exchange-name="fanout-exchange"
                                       reply-channel="reply"/>
    
    <rabbit:connection-factory id="connectionFactory" />
    
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory" reply-timeout="-1" />
    
    <rabbit:admin connection-factory="connectionFactory" />
    
    <rabbit:queue name="a-queue"/>
    <rabbit:queue name="b-queue"/>
    
    <rabbit:fanout-exchange name="fanout-exchange">
        <rabbit:bindings>
            <rabbit:binding queue="a-queue" />
            <rabbit:binding queue="b-queue" />
        </rabbit:bindings>
    </rabbit:fanout-exchange>
    
    
    
    我的rabbitMQ配置如下:

    <int:publish-subscribe-channel id="output" apply-sequence="true"/>
    
    <int:channel id="reply">
        <int:interceptors>
            <int:wire-tap channel="logger"/>
        </int:interceptors>
    </int:channel>
    
    <int:aggregator input-channel="reply" method="combine">
        <bean class="example.SimpleAggregator"/>
    </int:aggregator>
    
    <int:logging-channel-adapter id="logger" level="INFO"/>
    
    <int:gateway id="senderGateway" service-interface="example.SenderGateway" default-request-channel="output" default-reply-channel="reply"/>
    
    <int-amqp:outbound-gateway request-channel="output"
                                       amqp-template="amqpTemplate" exchange-name="fanout-exchange"
                                       reply-channel="reply"/>
    
    <rabbit:connection-factory id="connectionFactory" />
    
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory" reply-timeout="-1" />
    
    <rabbit:admin connection-factory="connectionFactory" />
    
    <rabbit:queue name="a-queue"/>
    <rabbit:queue name="b-queue"/>
    
    <rabbit:fanout-exchange name="fanout-exchange">
        <rabbit:bindings>
            <rabbit:binding queue="a-queue" />
            <rabbit:binding queue="b-queue" />
        </rabbit:bindings>
    </rabbit:fanout-exchange>
    
    
    
    消费者看起来是这样的:

    <int:channel id="input"/>
    
    <int-amqp:inbound-gateway request-channel="input" queue-names="a-queue" connection-factory="connectionFactory" concurrent-consumers="1"/>
    
    <bean id="listenerService" class="example.ListenerService"/>
    
    <int:service-activator input-channel="input" ref="listenerService" method="receiveMessage"/>
    
    
    
    任何建议都很好,我怀疑我在某个地方弄错了方向

    基于Gary评论的新出站spring配置:

    <int:channel id="output"/>
    
    <int:header-enricher input-channel="output" output-channel="output">
        <int:correlation-id expression="headers['id']" />
    </int:header-enricher>
    
    <int:gateway id="senderGateway" service-interface="example.SenderGateway" default-request-channel="output" default-reply-timeout="5000" default-reply-channel="reply" />
    
    <int-amqp:outbound-gateway request-channel="output"
                                       amqp-template="amqpTemplate" exchange-name="fanout-exchange"
                                       reply-channel="reply"
                                       mapped-reply-headers="amqp*,correlationId" mapped-request-headers="amqp*,correlationId"/>
    
    <int:channel id="reply"/>
    
    <int:aggregator input-channel="reply" output-channel="reply" method="combine" release-strategy-expression="size() == 2">
        <bean class="example.SimpleAggregator"/>
    </int:aggregator>
    

    问题是S.I.不知道扇出交换机的拓扑结构

    解决这个问题的最简单方法是使用自定义发布策略

    release-strategy-expression="size() == 2"
    
    在聚合器上(假设扇出为2)。因此,您不需要序列大小;您可以使用标题充实器避免“滥用”发布/订阅频道

        <int:header-enricher input-channel="foo" output-channel="bar">
            <int:correlation-id expression="T(java.util.UUID).randomUUID().toString()" />
        </int:header-enricher>
    

    到您的amqp端点。

    即使这个问题已经3年了,我还是要回答它,因为我有同样的问题

    SpringIntegration的一个实现听起来很像您最初的问题

    以下是来自

    它是一个复合端点,目标是向 收件人并聚合结果

    以前,模式可以使用离散组件进行配置, 此增强带来了更方便的配置

    ScatterGatherHandler是一个请求-应答端点,它结合了 PublishSubscribeChannel(或RecipientListRouter)和 聚合MessageHandler。请求消息将被发送到分散服务器 通道和ScatterGatherHandler等待来自 要发送到outputChannel的聚合器


    谢谢Gary,这让我走得更远了,现在的问题是我的出站网关似乎没有等待消息的响应。消费者可以很好地(从扇出交换)接收消息,我可以看到他们都在回复同一个rabbitmq队列(从调试),但我没有从发送者那里收到回复。我必须将amqp*添加到mapped request headers属性中,否则标准amqp标头将丢失。我没有注意到您正在使用网关-网关只处理对请求的单个答复。您需要使用出站适配器发送请求,使用入站适配器接收回复。您需要手动填充标头,以便2个使用者上的入站网关知道如何回复。