title: Spring Cloud Stream RabbitMQ
body: <p>I am trying to understand why I would want to use Spring cloud stream with RabbitMQ. I've had a look at the RabbitMQ Spring tutorial 4 (<a href="https://www.rabbitmq.com/tutorials/tutorial-four-spring-amqp.html" rel="nofollow noreferrer">https://www.rabbitmq.com/tutorials/tutorial-four-spring-amqp.html</a>) which is basically what I want to do. It creates a direct exchange with 2 queues attached and depending on the routing key a message is either routed to Q1 or to Q2. </p>
  
  <p>The whole process is pretty straight forward if you look at the tutorial, you create all the parts, bind them together and youre ready to go. </p>
  
  <p>I was wondering what benefit I would gain in using Sing Cloud Stream and if that is even the use case for it. It was easy to create a simple exchange and even defining destination and group was straight forward with stream. So I thought why not go further and try to handle the tutorial case with stream.</p>
  
  <p>I have seen that Stream has a <code>BinderAwareChannelResolver</code> which seems to do the same thing. But I am struggling to put it all together to achieve the same as in the RabbitMQ Spring tutorial. I am not sure if it is a dependency issue, but I seem to misunderstand something fundamentally here, I thought something like: </p>
  
  <pre><code>spring.cloud.stream.bindings.output.destination=myDestination
  spring.cloud.stream.bindings.output.group=consumerGroup
  spring.cloud.stream.rabbit.bindings.output.producer.routing-key-expression='key'
  </code></pre>
  
  <p>should to the trick. </p>
  
  <p>Is there anyone with a minimal example for a source and sink which basically creates a direct exchange, binds 2 queues to it and depending on routing key routes to either one of those 2 queues like in <a href="https://www.rabbitmq.com/tutorials/tutorial-four-spring-amqp.html" rel="nofollow noreferrer">https://www.rabbitmq.com/tutorials/tutorial-four-spring-amqp.html</a>? </p>
  
  <p><strong>EDIT</strong>:</p>
  
  <p>Below is a minimal set of code which demonstrates how to do what I asked. I did not attach the <code>build.gradle</code> as it is straight forward (but if anyone is interested, let me know)</p>
  
  <p><code>application.properties</code>: setup the producer</p>
  
  <pre><code>spring.cloud.stream.bindings.output.destination=tut.direct
  spring.cloud.stream.rabbit.bindings.output.producer.exchangeType=direct
  spring.cloud.stream.rabbit.bindings.output.producer.routing-key-expression=headers.type
  </code></pre>
  
  <p><code>Sources.class</code>: setup the producers channel</p>
  
  <pre><code>public interface Sources {
  
      String OUTPUT = "output";
  
      @Output(Sources.OUTPUT)
      MessageChannel output();
  }
  </code></pre>
  
  <p><code>StatusController.class</code>: Respond to rest calls and send message with specific routing keys</p>
  
  <pre><code>/**
   * Status endpoint for the health-check service.
   */
  @RestController
  @EnableBinding(Sources.class)
  public class StatusController {
  
      private int index;
  
      private int count;
  
      private final String[] keys = {"orange", "black", "green"};
  
      private Sources sources;
  
      private StatusService status;
  
      @Autowired
      public StatusController(Sources sources, StatusService status) {
          this.sources = sources;
          this.status = status;
      }
  
      /**
       * Service available, service returns "OK"'.
       * @return The Status of the service.
       */
      @RequestMapping("/status")
      public String status() {
          String status = this.status.getStatus();
  
          StringBuilder builder = new StringBuilder("Hello to ");
          if (++this.index == 3) {
              this.index = 0;
          }
          String key = keys[this.index];
          builder.append(key).append(' ');
          builder.append(Integer.toString(++this.count));
          String payload = builder.toString();
          log.info(payload);
  
          // add kv pair - routingkeyexpression (which matches 'type') will then evaluate
          // and add the value as routing key
          Message&lt;String&gt; msg = new GenericMessage&lt;&gt;(payload, Collections.singletonMap("type", key));
          sources.output().send(msg);
  
          // return rest call
          return status;
      }
  }
  </code></pre>
  
  <p>consumer side of things, properties: </p>
  
  <pre><code>spring.cloud.stream.bindings.input.destination=tut.direct
  spring.cloud.stream.rabbit.bindings.input.consumer.exchangeType=direct
  spring.cloud.stream.rabbit.bindings.input.consumer.bindingRoutingKey=orange
  spring.cloud.stream.bindings.inputer.destination=tut.direct
  spring.cloud.stream.rabbit.bindings.inputer.consumer.exchangeType=direct
  spring.cloud.stream.rabbit.bindings.inputer.consumer.bindingRoutingKey=black
  </code></pre>
  
  <p><code>Sinks.class</code>:</p>
  
  <pre><code>public interface Sinks {
  
      String INPUT = "input";
  
      @Input(Sinks.INPUT)
      SubscribableChannel input();
  
      String INPUTER = "inputer";
  
      @Input(Sinks.INPUTER)
      SubscribableChannel inputer();
  }
  </code></pre>
  
  <p><code>ReceiveStatus.class</code>: Receive the status:</p>
  
  <pre><code>@EnableBinding(Sinks.class)
  public class ReceiveStatus {
      @StreamListener(Sinks.INPUT)
      public void receiveStatusOrange(String msg) {
         log.info("I received a message. It was orange number: {}", msg);
      }
  
      @StreamListener(Sinks.INPUTER)
      public void receiveStatusBlack(String msg) {
          log.info("I received a message. It was black number: {}", msg);
      }
  }
  </code></pre>