简体   繁体   English

当响应来自使用 Spring 集成 DSL 的 rabbitMQ 回复队列时,如何实现 HTTP 请求/回复?

[英]How to implement HTTP request/reply when the response comes from a rabbitMQ reply queue using Spring Integration DSL?

I am trying to implement a HTTP request/reply using separate RabbitMQ queues in Spring Integration DSL.我正在尝试使用 Spring 集成 DSL 中的单独 RabbitMQ 队列来实现 HTTP 请求/回复。 It's similar to Spring IntegrationFlow http request to amqp queue .它类似于Spring IntegrationFlow http request to amqp queue The difference is I want the response back to the original http caller.不同之处在于我希望将响应返回给原始 http 调用者。 I could see the test http post message successfully passed to the request queue and transformed (into upper case) into the response queue.我可以看到测试 http 发布消息成功传递到请求队列并转换(大写)到响应队列。 The message was consumed from the response queue as well but never returned back to the caller(http://localhost:8080/Tunner).该消息也从响应队列中消耗,但从未返回给调用者(http://localhost:8080/Tunner)。 Eventually the call timed out with 500 error.最终调用超时,出现 500 错误。 I am new to this so there could be something I totally missed.我是新手,所以可能有一些我完全错过的东西。 Could someone provide suggestion?有人可以提供建议吗? The code is as follows:代码如下:

public class TunnelApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(TunnelApplication.class, args);
    }

    @Value("${outboundQueue}")
    private String outboundQueue;

    @Value("${inboundQueue}")
    private String inboundQueue;

    private ConnectionFactory rabbitConnectionFactory;

    @Autowired
    public TunnelApplication(ConnectionFactory factory) {
        rabbitConnectionFactory = factory;
    }

    @Bean
    public Queue targetQueue()
    {
        return new Queue(outboundQueue, true, false, true);
    }

    @Bean
    public Queue requestQueue()
    {
        return new Queue(inboundQueue, true, false, true);
    }

    @Bean
    public Jackson2JsonMessageConverter jsonMessageConverter()
    {
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    public AmqpTemplate amqpTemplate()
    {
        RabbitTemplate result = new RabbitTemplate(rabbitConnectionFactory);
        result.setMessageConverter(jsonMessageConverter());
        result.setDefaultReceiveQueue(outboundQueue);
        //result.setReplyAddress(outboundQueue);
        result.setReplyTimeout(60000);
        return result;
    }

    @Bean
    public IntegrationFlow sendReceiveFlow(RabbitTemplate amqpTemplate) {
        return IntegrationFlows
                .from(Http.inboundGateway("/tunnel"))
                .handle(Amqp.outboundGateway(amqpTemplate)
                        .routingKey(inboundQueue)
                        .returnChannel(amqpOutboundChannel()))
                .log()
                .bridge(null)
                .get();
    }

    @Bean
    public IntegrationFlow rabbitToWeb(RabbitTemplate amqpTemplate, ConnectionFactory connectionFactory) {
        return IntegrationFlows.from(Amqp.inboundGateway(connectionFactory, requestQueue()))
                .transform(String.class, String::toUpperCase)
                .log()
                .handle(Amqp.outboundGateway(amqpTemplate).routingKey(outboundQueue))
                .log()
                .bridge(null)
                .get();
    }

    @Bean
    public IntegrationFlow replyBackToHttp(RabbitTemplate amqpTemplate, ConnectionFactory connectionFactory) {
        return IntegrationFlows.from(Amqp.inboundGateway(connectionFactory, targetQueue()))
                .handle(Http.outboundGateway("http://localhost:8080/tunnel")
                       .expectedResponseType(String.class))
                .log()
                .bridge(null)
                .channel(amqpOutboundChannel())
                .get();
    }

    @Bean
    public MessageChannel amqpOutboundChannel() {
    return new DirectChannel();
}

We have also tried the following code (by my coworker) and we didn't get the response either:我们还尝试了以下代码(由我的同事编写),但我们也没有得到响应:

@Configuration
@EnableIntegration
public class FlowConfig {

 

   @Value("${routingKey}")
   private String routingKey;

 

   @Value("${rabbitSinkChannel}")
   private String rabbitSinkChannel;

 

   @Bean
   public MessageChannel rabbitSinkChannel(ConnectionFactory connectionFactory) {
      return
         Amqp
         .channel(rabbitSinkChannel, connectionFactory)
         .get();
   }

 

   @Bean
   public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
      return new RabbitTemplate(connectionFactory);
   }

 

   @Bean
   public IntegrationFlow httpFlow(RabbitTemplate rabbitTemplate, ConnectionFactory connectionFactory) {
      MessageChannel rabbitSinkChannel = rabbitSinkChannel(connectionFactory);

 

      return IntegrationFlows
         .from(
            Http.inboundGateway("/sendreceive")
         )
         .handle(
            Amqp.outboundGateway(rabbitTemplate)
               .routingKey(routingKey)
               .returnChannel(rabbitSinkChannel)
         )
         .channel(rabbitSinkChannel) // or .handle? if so, what?

 

         .get();
   }
}

You probably misunderstood what is returnChannel on the Amqp.outboundGateway and try to rely your logic on it.您可能误解了returnChannel上的Amqp.outboundGateway是什么,并尝试依赖您的逻辑。 Please, make yourself familiar with that Publisher Confirms and Returns feature: https://docs.spring.io/spring-amqp/docs/current/reference/html/#cf-pub-conf-ret .请熟悉发布者确认和退货功能: https://docs.spring.io/spring-amqp/docs/current/reference/html/#cf-pub-conf-ret

It is also not clear what is a replyBackToHttp flow purpose, but it confuses at the moment with mixed references to other beans.还不清楚什么是replyBackToHttp流目的,但目前它与对其他 bean 的混合引用混淆了。

You probably need to investigate what is a request-reply configuration from Spring AMQP respective and you would probably don't try to use another queue for replies.您可能需要分别从 Spring AMQP 调查什么是请求-回复配置,并且您可能不会尝试使用另一个队列进行回复。 Although it is still possible: see replyAddress property or RabbitTemplate : https://docs.spring.io/spring-amqp/docs/current/reference/html/#request-reply虽然它仍然是可能的:请参阅replyAddress属性或RabbitTemplatehttps://docs.spring.io/spring-amqp/docs/current/reference/html/#request-reply

The following update works (I also removed the replyBackToHttp() method):以下更新有效(我还删除了 replyBackToHttp() 方法):

@Bean
public AmqpTemplate amqpTemplate()
{
    RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory);
    rabbitTemplate.setMessageConverter(jsonMessageConverter());
    //result.setDefaultReceiveQueue(outboundQueue);
    rabbitTemplate.setReplyAddress(outboundQueue);
    rabbitTemplate.setReplyTimeout(60000);
    rabbitTemplate.setUseDirectReplyToContainer(false);
    return rabbitTemplate;
}

@Bean
public SimpleMessageListenerContainer replyListenerContainer() {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(rabbitConnectionFactory);
    container.setQueues(replyQueue());
    container.setMessageListener((MessageListener) amqpTemplate());
    return container;
}

Here's the almost complete solution to anyone that's frustrated and just wants to move on.对于任何感到沮丧并且只想继续前进的人来说,这是几乎完整的解决方案。

package com.scdf.poc.config;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.amqp.dsl.Amqp;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.http.dsl.Http;
@Configuration
@EnableIntegration
public class FlowConfig {
   @Value("${rabbitSource}")
   private String rabbitSource;
   @Value("${rabbitSink}")
   private String rabbitSink; // Note: Has to be manually created in rabbit mq, the SCDF flows won't auto create this
   @Bean
   public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
      RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
      rabbitTemplate.setReplyAddress(rabbitSink);
      return rabbitTemplate;
   }
   @Bean
   public SimpleMessageListenerContainer simpleMessageListenerContainer(RabbitTemplate rabbitTemplate, ConnectionFactory connectionFactory) {
      SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
      container.setConnectionFactory(connectionFactory);
      container.setQueueNames(rabbitSink);
      container.setMessageListener(rabbitTemplate);
      return container;
   }
   @Bean
   public IntegrationFlow httpFlow(RabbitTemplate rabbitTemplate) {
      return IntegrationFlows
         .from(
            Http.inboundGateway("/sendreceive")
               .requestPayloadType(String.class)
         )
         .handle(
            Amqp.outboundGateway(rabbitTemplate)
               .routingKey(rabbitSource)
         )
         .get();
   }
}

application.properties - note that SCDF uses the stream name as both prefix and suffix for queue names application.properties - 注意 SCDF 使用 stream 名称作为队列名称的前缀和后缀

rabbitSource=pocStream.rabbitSource.pocStream
rabbitSink=pocStream.rabbitSink.pocStream

SCDF stream definition for pocStream - this just echos the request back pocStream 的 SCDF stream 定义 - 这只是回显请求

rabbitSource: rabbit --queues=rabbitSource | bridge | rabbitSink: rabbit --routing-key=pocStream.rabbitSink.pocStream

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用Spring Integration Java DSL将消息发送到Rabbitmq队列 - How to send message to the rabbitmq queue using spring integration java DSL 使用原始(不使用Gateway)Spring Integration时如何关联请求和回复? - How to correlate request & reply when using raw (not using Gateway) Spring Integration? Spring Boot和RabbitMQ的异步请求-答复 - Asynchronous request-reply with Spring Boot and RabbitMQ 如何使用spring-amqp配置Rabbitmq回复队列? - How to configure rabbitmq reply queues using spring-amqp? 如何异步发送消息以排队它们而不等待使用java中的rabbitmq在spring amqp中回复每条消息? - How to send messages asynchronously to queue them up without waiting for reply of each message in spring amqp using rabbitmq in java? RabbitMQ固定答复队列配置 - RabbitMQ fixed reply queue configuration 如果对HA使用Rabbitmq镜像队列,是否应定义答复队列持久性? - if using rabbitmq mirror queue for HA, should define reply queue durable? 使用 AsyncRabbitTemplate::sendAndReceive 时回复超时 - RabbitMQ - Reply timeout when using AsyncRabbitTemplate::sendAndReceive - RabbitMQ 由于网段,带有RabbitMq请求/响应的MassTransit错误的答复地址 - MassTransit with RabbitMq Request/Response wrong reply address because of network segments 如何使用RabbitMq直接回复队列扩展 - How to use RabbitMq Direct reply-to queue extension
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM