Section 2 Fanout Routing Switches: Subscription Publishing Mode

Posted by scott.stephan on Mon, 06 May 2019 17:00:03 +0200

1. Basic Model

P stands for the producer and is the party that sends the message.

X represents the router switch, which receives messages from senders and forwards them to all queues that subscribe to it.

The red part is the queue.If it is interested in a switch, it can bind itself to it. The technical term is binding.

        

Switch X will distribute messages directly to the queue subscribing to any message it receives.This is equivalent to the publish-subscribe mode.This is the most direct form of broadcasting, which forwards whatever message the router receives to all queues subscribing to it without BB.

In RabbitMQ, a Fanout-type switch (router) forwards data directly to the queue bound to it.

2. Use Code

There are three classes, the first is the sender and the second and third are the two receivers.

Code outline:

We created a Fanout-type switch.Two more queues were created, both bound to this Fanout-type switch.

Then we send a message to this switch to see if the queues bound to it can receive data.

Sender.java

package com.safesoft.fanoutexchanger.mq02;


import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.ExchangeTypes;

/**
 * @author jay.zhou
 * @date 2019/4/23
 * @time 10:10
 */
public class Producer {
    private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
    private static final String EXCHANGE_NAME = "local::mq02:exchange:e01";

    public static void main(String[] args) {
        try {
            //Connection Manager: The manager where our application connects to RabbitMQ.
            ConnectionFactory factory = new ConnectionFactory();
            //Set RabbitMQ Server Address
            factory.setHost("127.0.0.1");
            //Set account password, default is guest/guest, so the next two lines can be omitted
            factory.setUsername("guest");
            factory.setPassword("guest");

            //Create a connection
            Connection connection = factory.newConnection();
            //Create a channel
            Channel channel = connection.createChannel();
            //Create a switch over a channel
            /**
             * The first parameter is the name of the switch
             * The second parameter is the type of switch Fanout:
             * fanout: Bind the queue directly to the router.After receiving a message, the router delivers the message directly to the queue without requiring a routing key.
             */
            channel.exchangeDeclare(EXCHANGE_NAME, ExchangeTypes.FANOUT);

            //Messages are transmitted in binary mode
            final String message = "China Unicom stock price has fallen again, unhappy";
            final byte[] msg = message.getBytes("UTF-8");

            //Send messages directly to the router.Routes post directly to queues subscribing to this router after receiving messages
            channel.basicPublish(EXCHANGE_NAME, "", null, msg);

            LOGGER.info("Message sent successfully:{}", message);
            channel.close();
            connection.close();
        } catch (Exception e) {
            LOGGER.error("an exception was occurred , caused by :{}", e.getMessage());
        }

    }

}


Receiver 1.java

package com.safesoft.fanoutexchanger.mq02;

import com.rabbitmq.client.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.ExchangeTypes;

import java.io.IOException;

/**
 * @author jay.zhou
 * @date 2019/4/23
 * @time 10:49
 */
public class Consume01 {
    private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
    private static final String EXCHANGE_NAME = "local::mq02:exchange:e01";
    private static final String QUEUE_NAME_01 = "local::mq02:queue:q01";
    private static final String QUEUE_NAME_02 = "local::mq02:queue:q02";

    public static void main(String[] args) {
        try {
            //Set RabbitMQ Server Information
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("127.0.0.1");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();

            //Declare a queue
            /**
             * The first parameter is queue: the name of the queue to create
             * The second parameter is durable: whether to persist or not.If true, message can be recovered after RabbitMQ crash
             * The third parameter is exclusive:true, which means that a queue can only be owned and consumed by one consumer
             * The fourth parameter is autoDelete:true, which means the queue will be automatically deleted if the server is not using it
             * The fifth parameter is arguments: other parameters
             */
            channel.queueDeclare(QUEUE_NAME_01, true, false, false, null);
            //Claim Switch
            channel.exchangeDeclare(EXCHANGE_NAME, ExchangeTypes.FANOUT);

            //In a fanout-type router, the routing key is invalid, so it is designed as an empty string
            final String routeKey = "";
            //Subscribe this queue to this router to indicate that the queue is interested in this router
            channel.queueBind(QUEUE_NAME_01, EXCHANGE_NAME, routeKey);

            Consumer consumer = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String message = new String(body, "UTF-8");
                    LOGGER.info("Recipient 1 receives the message:{}", message);
                }
            };
            //Queue 1 acknowledges receipt of message
            channel.basicConsume(QUEUE_NAME_01, true, consumer);

        } catch (Exception e) {
            LOGGER.error("an exception was occurred , caused by :{}", e.getMessage());
        }

    }
}

Receiver 2.java

package com.safesoft.fanoutexchanger.mq02;

import com.rabbitmq.client.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.ExchangeTypes;

import java.io.IOException;

/**
 * @author jay.zhou
 * @date 2019/4/23
 * @time 10:49
 */
public class Consume02 {
    private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
    private static final String EXCHANGE_NAME = "local::mq02:exchange:e01";
    private static final String QUEUE_NAME_01 = "local::mq02:queue:q01";
    private static final String QUEUE_NAME_02 = "local::mq02:queue:q02";

    public static void main(String[] args) {
        try {
            //Set RabbitMQ Server Information
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("127.0.0.1");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();

            //Declare a queue
            /**
             * The first parameter is queue: the name of the queue to create
             * The second parameter is durable: whether to persist or not.If true, message can be recovered after RabbitMQ crash
             * The third parameter is exclusive:true, which means that a queue can only be owned and consumed by one consumer
             * The fourth parameter is autoDelete:true, which means the queue will be automatically deleted if the server is not using it
             * The fifth parameter is arguments: other parameters
             */
            channel.queueDeclare(QUEUE_NAME_02, true, false, false, null);
            //Claim Switch
            channel.exchangeDeclare(EXCHANGE_NAME, ExchangeTypes.FANOUT);

            //In a fanout-type router, the routing key is invalid, so it is designed as an empty string
            final String routeKey = "";
            //Subscribe this queue to this router to indicate that the queue is interested in this router
            channel.queueBind(QUEUE_NAME_02, EXCHANGE_NAME, routeKey);

            Consumer consumer = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String message = new String(body, "UTF-8");
                    LOGGER.info("Recipient 2 received the message:{}", message);
                }
            };
            //Queue 1 acknowledges receipt of message
            channel.basicConsume(QUEUE_NAME_02, true, consumer);

        } catch (Exception e) {
            LOGGER.error("an exception was occurred , caused by :{}", e.getMessage());
        }

    }
}

The sender class Producer can be run a few more times first.I ran it twice.

The message is: The message was sent successfully:'Unhappy that the stock price of China Unicom has fallen again'.When I wrote this article, I lost money on the stock market again.

       

Run Receiver Class separately, Receiver No. 1 and No. 2 both receive the news that the stock has fallen (in other words, how can I always lose money in my stock speculation)?

 

3. Summary

Fanout-type routers do not handle routing keys.You simply bind the queue to the switch.A message sent to a switch is forwarded to all queues bound to the switch.Much like subnet broadcasting, hosts within each subnet receive a replicated message.The Fanout switch forwards messages the fastest.

4. Download of Source Code

Source code address: https://github.com/hairdryre/Study_RabbitMQ

Next: Section 2 Fanout Routing Switches: Subscription Publishing Mode

Topics: RabbitMQ Java github