Spring boot integrates RabbitMQ: Routing

Keywords: Spring Java RabbitMQ snapshot

In this article, we'll implement another function - to subscribe to only a few messages. For example, we only need to write the serious error log information to the log file (stored on disk), but still output all the log information to the console
Binding
In the previous example, we have created the binding. You can recall the following code in our Tut3Config file:

@Bean
public Binding binding1(FanoutExchange fanout, Queue autoDeleteQueue1) {
    return BindingBuilder.bind(autoDeleteQueue1).to(fanout);
}

binding refers to the relationship between exchange and queue. It can be simply understood that the queue is interested in messages from the exchange.
Binding can use an additional parameter routingKey. We pass in the switch and queue to BindingBuilder, and bind routingKey to the switch as follows:

@Bean
public Binding binding1a(DirectExchange direct, Queue autoDeleteQueue1) {
    return BindingBuilder.bind(autoDeleteQueue1)
        .to(direct)
        .with("orange");
}

The meaning of routingKey depends on the exchange type. For example, the fanout exchange we used before will ignore its value.

Direct exchange
Our log system broadcasts all messages to all consumers. We intend to extend it to filter messages based on the severity of the log. For example, we may just want to write the more serious error log to disk to avoid wasting disk space on warning or info logs.

The fanout exchange we use is not flexible enough - all it can do is broadcast.

We will use direct exchange instead. The routing algorithm is simple - the switch will match the binding key and routing key exactly to determine which queue the message should be distributed to.
The following figure is a good description of this scenario:

In this scenario, we can see that direct exchange X is bound to two queues. The first queue uses orange as the binding key, the second queue has two bindings, one uses black as the binding key, and the other uses green.

In this way, when the message with the routing key orange is published to the switch, it will be routed to queue Q1. Messages with the routing key of black or green will be routed to Q2. All other messages will be discarded.

Multiple bindings

It is possible to use the same binding key for multiple queues. In this example, we can add a binding between X and Q1, using the black binding key. In this way, direct exchange behaves the same as fanout exchange, broadcasting messages to all matching queues. Messages with the black routing key are sent to both Q1 and Q2.

Publish news
We will use the above model as our routing system to send messages to direct exchange instead of fanout exchange. We will use color as the routing key so that consumers can consume the corresponding messages by selecting the color they want to receive (or subscribe to).

We do some Spring startup configuration in Tut4Config. We need to establish a switch first

@Bean
public DirectExchange direct() {
    return new DirectExchange("tut.direct");
}

The way messages are received is the same as in the previous tutorial, but there are some differences - we need to create a new binding for each color of interest.
To understand the spring cloud architecture, we can ask for three five three six two four seven two five nine

@Bean
public Binding binding1a(DirectExchange direct, Queue autoDeleteQueue1) {
    return BindingBuilder.bind(autoDeleteQueue1)
        .to(direct)
        .with("orange");

Code integration

Producer

public class Tut4Sender {

   @Autowird 
    private AmqpTemplate template;

    @Autowird
    private DirectExchange direct;

    private int index;

    private int count;

    private final String[] keys = {"orange", "black", "green"};

    @Scheduled(fixedDelay = 1000, initialDelay = 500)
    public void send() {
        StringBuilder builder = new StringBuilder("Hello to ");
        if (++this.index == 3) {
            this.index = 0;
        }
        String key = keys[this.index];
        builder.append(key).append(' ').append(Integer.toString(++this.count));
        String message = builder.toString();
        template.convertAndSend(direct.getName(), key, message);
        System.out.println(" [x] Sent '" + message + "'");
    }

}

Consumer

public class Tut4Receiver {

    @RabbitListener(queues = "#{autoDeleteQueue1.name}")
    public void receiver1(String in) throws InterruptedException {
        receiver(in, 1);
    }

    @RabbitListener(queues = "#{autoDeleteQueue2.name}")
    public void receiver2(String in) throws InterruptedException {
        receiver(in, 2);
    }

    private void receiver(String in, int instance) throws InterruptedException {
        StopWatch watch = new StopWatch();
        watch.start();
        System.out.println("instance " + instance + " [x] Received '" + in + "'");
        doWork(in);
        watch.stop();
        System.out.println("instance " + instance + " [x] Done in " +
                watch.getTotalTimeSeconds() + "s");
    }

    private void doWork(String in) throws InterruptedException {
        for (char ch : in.toCharArray()) {
            if (ch == '.') {
                Thread.sleep(1000);
            }
        }
    }

}

Configuration class

Profile({"tut4", "routing"})
@Configuration
public class Tut4Config {


    @Bean
    public DirectExchange direct() {
        return new DirectExchange("tut.direct");
    }

   @Profile ("receiver")
    private static class ReceiverConfig {

        @Bean
        public Queue autoDeleteQueue1() {
            return new AnonymousQueue();
        }

        @Bean
        public Queue autoDeleteQueue2() {
            return new AnonymousQueue();
        }

        @Bean
        public Binding binding1a(DirectExchange direct, Queue autoDeleteQueue1) {
            return BindingBuilder.bind(autoDeleteQueue1)
                    .to(direct)
                    .with("orange");
        }

        @Bean
        public Binding binding1b(DirectExchange direct, Queue autoDeleteQueue1) {
            return BindingBuilder.bind(autoDeleteQueue1)
                    .to(direct)
                    .with("black");
        }

        @Bean
        public Binding binding2a(DirectExchange direct, Queue autoDeleteQueue2) {
            return BindingBuilder.bind(autoDeleteQueue2)
                    .to(direct)
                    .with("green");
        }

        @Bean
        public Binding binding2b(DirectExchange direct, Queue autoDeleteQueue2) {
            return BindingBuilder.bind(autoDeleteQueue2)
                    .to(direct)
                    .with("black");
        }

       @Bean 
        public Tut4Receiver receiver() {
            return new Tut4Receiver();
        }

    }Profile("sender")
    @Bean
    public Tut4Sender sender() {
        return new Tut4Sender();
    }

}

Function
maven compilation

mvn clean package -Dmaven.test.skip=true
Function

java -jar target/rabbitmq-tutorial-0.0.1-SNAPSHOT.jar --spring.profiles.active=tut4,receiver --tutorial.client.duration=60000
java -jar target/rabbitmq-tutorial-0.0.1-SNAPSHOT.jar --spring.profiles.active=tut4,sender --tutorial.client.duration=60000
output

// Sender
Ready ... running for 60000ms
[x] Sent 'Hello to black 1'
[x] Sent 'Hello to green 2'
[x] Sent 'Hello to orange 3'
[x] Sent 'Hello to black 4'

// Receiver
Ready ... running for 60000ms
instance 2 [x] Received 'Hello to black 1'
instance 1 [x] Received 'Hello to black 1'
instance 2 [x] Done in 0.0s
instance 1 [x] Done in 0.0s
instance 2 [x] Received 'Hello to green 2'
instance 2 [x] Done in 0.0s
instance 1 [x] Received 'Hello to orange 3'
instance 1 [x] Done in 0.0s
instance 1 [x] Received 'Hello to black 4'
instance 1 [x] Done in 0.0s
instance 2 [x] Received 'Hello to black 4'
instance 2 [x] Done in 0.0s

101 original articles published, 105 praised, 5933 visited
Private letter follow

Posted by user___ on Thu, 05 Mar 2020 19:17:15 -0800