RabbitMQ middleware explanation and use

Table of contents

1. MQ message middleware

1.2. Why use MQ?

2. Advantages and disadvantages of MQ

2.1. Advantages

2.1.1. Application decoupling

2.1.2. Asynchronous speed-up

2.1.3. Peak shaving and valley filling

 2.2. Disadvantages

2.2.1. Reduced system availability

2.2.2. Increased system complexity

2.2.3. Consistency issue

3. Common MQ components

4. What is RabbitMQ?

5. RabbitMQ principle

 5.1. Glossary

6. RabbitMQ working mode

6.1. simple (simple mode)

6.2. WorkQueues (working mode)

6.3. Publish/Subscribe (publish and subscribe mode)

6.4. Routing (routing mode)

         6.5. Topics (theme mode)


1. MQ message middleware

The full name of MQ is Message Queue (Message Queue), which is a container that saves messages during the transmission process of messages. It is a method of communication between applications.

1.2. Why use MQ?

In the project, some time-consuming operations that do not require immediate return can be extracted for asynchronous processing . This asynchronous processing method greatly saves the server's request response time, thus improving the system throughput .

2. Advantages and disadvantages of MQ

2.1. Advantages

2.1.1. Application decoupling

Take e-commerce applications as an example. The applications include order systems, inventory systems, logistics systems, and payment systems. After the user creates an order, if the inventory system, logistics system, and payment system are coupled and called, if any subsystem fails, the order operation will be abnormal. When converted to a message queue-based approach, the problems of inter-system calls will be greatly reduced. For example, a logistics system will take a few minutes to repair due to a failure. During these few minutes, the content to be processed by the logistics system is cached in the message queue, and the user's order operation can be completed normally. When the logistics system is restored, order information can continue to be processed. Intermediate users will not feel the failure of the logistics system, which improves the availability of the system.

 

2.1.2. Asynchronous speed-up

 

The time it takes to complete the order above: 20 + 300 + 300 + 300 = 920ms. After the user clicks the order button, he needs to wait 920ms to get the order response, which is too slow!

Using MQ can solve the above problems

 

After the user clicks the order button, he only needs to wait 25ms to get the order response (20 + 5 = 25ms). Improve user experience and system throughput (number of requests processed per unit time).

2.1.3. Peak shaving and valley filling

For example, if the order system can process up to a thousand orders, this processing capacity is more than enough to handle orders during normal periods. During normal periods, we can return results in one second after placing orders. However, during the peak period, if there are 2,000 orders placed, the operating system cannot handle it. It can only limit the number of orders exceeding 1,000 and not allow users to place orders. Using the message queue as buffer, we can cancel this restriction and spread the orders placed within one second into a period of time for processing. At this time, some users may not receive the successful order operation more than ten seconds after placing the order, but it is better than not being able to place the order. The single experience is better. To put it simply: When the number of visits increases sharply, but the application still cannot be stopped, for example, there are many people placing orders during "Double Eleven", but the Taobao application still needs to run, so you can use message middleware and queue. Form reduces the stress of surprise visits.

 

After using MQ, the speed of consuming messages is limited to 1000. In this way, the data generated during the peak period will be backlogged in MQ, and the peak period will be "cut". However, due to the backlog of messages, in the period after the peak period, During this time, the speed of consuming messages will still remain at 1,000 until the backlog of messages is consumed. This is called "filling the valley".

After using MQ, system stability can be improved.

 2.2. Disadvantages

2.2.1. Reduced system availability

The more external dependencies introduced into the system, the worse the stability of the system. Once MQ goes down, it will have an impact on the business.

How to ensure the high availability of MQ?

2.2.2. Increased system complexity

The addition of MQ has greatly increased the complexity of the system. In the past, synchronous remote calls were made between systems, but now asynchronous calls are made through MQ.

How to ensure that messages are not consumed repeatedly? How to deal with message loss? So ensure the order of message delivery?

2.2.3. Consistency issue

After system A finishes processing the business, it sends message data to systems B, C, and D through MQ. If system B and system C process successfully, system D fails to process.

How to ensure the consistency of message data processing?

3. Common MQ components

There are currently many MQ products in the industry, such as RabbitMQ, RocketMQ, ActiveMQ, Kafka, ZeroMQ, MetaMq, etc. There are also cases where Redis is directly used as a message queue. Each of these message queue products has its own focus. When selecting the actual model, it needs to be combined own needs and MQ product features.

 4. What is RabbitMQ?

Released in 2007, it is a reusable enterprise messaging system based on AMQP (Advanced Message Queuing Protocol). It is one of the most mainstream message middleware currently.

 RabbitMQ is an open source implementation of AMQP (Advanced Message Queue Advanced Message Queuing Protocol) developed by erlang. Due to the high concurrency characteristics of the erlang language, it has good performance. It is essentially a queue, FIFO first-in, first-out, and the content stored in it is message.

RabbitMQ is a messaging middleware: it accepts and forwards messages. You can think of it as a courier site. When you want to send a package, you put your package at the courier station, and the courier will eventually deliver your package to the recipient. According to this logic, RabbitMQ is a courier. Station, a courier will help you deliver the express. The main difference between RabbitMQ and express delivery stations is that it does not process express mail but receives, stores and forwards message data.

5. RabbitMQ principle

 5.1. Glossary

  1. Broker : An application that receives and distributes messages. RabbitMQ Server is the Message Broker.

  2. Connection : TCP connection between publisher/consumer and broker

  3. Channel : If a Connection is established every time RabbitMQ is accessed, the overhead of establishing a TCP Connection will be huge and the efficiency will be low when the message volume is large. Channel is a logical connection established inside the connection. If the application supports multi-threading, each thread usually creates a separate channel for communication. The AMQP method contains the channel id to help the client and message broker identify the channel, so the channels are completely isolated. of. Channel, as a lightweight Connection, greatly reduces the operating system's overhead in establishing TCP connections.

  4. Exchange : The message reaches the first stop of the broker. According to the distribution rules, it matches the routing key in the query table and distributes the message to the queue. Commonly used types are: direct (point-to-point), topic (publish-subscribe) and fanout (multicast)

  5. Queue : The message is finally sent here to wait for the consumer to pick it up

  6. Binding : The virtual connection between exchange and queue. The binding can contain routing key. Binding information is saved to the query table in exchange and used as the basis for message distribution.

  7. Virtual host : Designed for multi-tenancy and security reasons, the basic components of AMQP are divided into a virtual group, similar to the namespace concept in the network. When multiple different users use the services provided by the same RabbitMQ server, multiple vhosts can be divided, and each user creates exchange/queue, etc. in their own vhost.

6. RabbitMQ working mode

RabbitMQ provides 6 working modes: simple mode, work queues, Publish/Subscribe publishing and subscription mode, Routing routing mode, Topics topic mode, RPC remote calling mode (remote calling, not quite MQ; we will not introduce it yet). Introduction to the corresponding mode on the official website: RabbitMQ Tutorials — RabbitMQ

 6.1. simple (simple mode)

In the model above, there are the following concepts:

  • P: Producer, which is the program that wants to send messages

  • C: Consumer: The receiver of the message will always wait for the message to arrive.

  • queue: message queue, red part in the picture. Similar to a mailbox, messages can be cached; producers deliver messages to it and consumers retrieve messages from it.

rely:

        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.16.0</version>
        </dependency>

Producer:

package simple;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


/**
 * @program: qy-rabbitmq
 * @description: 简单生产者
 * @author: 
 * @create: 2023-07-12 16:41
 **/
public class SimpleProduct {
    public static void main(String[] args) throws Exception{
        //创建连接工厂并设置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        //设置rabbitmq服务的地址,默认localhost
        factory.setHost("192.168.232.166");
        //设置rabbitmq的端口号 AMQP端口
        factory.setPort(5672);
        //设置账号 默认guest
        factory.setUsername("lx");
        //设置密码 默认guest
        factory.setPassword("lx");
        //设置虚拟机 默认 /
        factory.setVirtualHost("/lx");

        //获取连接对象
        Connection connection = factory.newConnection();
        //获取channel对象
        Channel channel = connection.createChannel();

        //创建队列
        /*
        *String queue, 队列的名称. 如果该名称不存在 则创建  如果存在则不创建
        * boolean durable, 该对象是否持久化  当rabbitmq重启后 队列就会消失
        *  boolean exclusive, 该队列是否被一个消费者独占
        * boolean autoDelete,当没有消费者时,该队列是否被自动删除
        * Map<String, Object> arguments: 额外参数的设置
        * */
        //存在该队列则不会创建
        channel.queueDeclare("hello_queue",true,false,false,null);

        //发送消息
      /*  String exchange, 交换机的名称 简单模式没有交换机使用""表示采用默认交换机
        String routingKey, 路由标识  如果是简单模式起名为队列的名称
        BasicProperties props, 消息的属性设置。 设置为null
        byte[] body: 消息的内容*/
        String msg = "hello rabbitmq------------";
        channel.basicPublish("","hello_queue",null,msg.getBytes());

        //关闭资源
        channel.close();
        connection.close();
    }

}

 consumer:

package simple;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @program: qy-rabbitmq
 * @description: 简单消费者
 * @author: 
 * @create: 2023-07-12 18:12
 **/
public class SimpleConsumer {
    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setVirtualHost("/lx");
        factory.setUsername("lx");
        factory.setPassword("lx");
        factory.setHost("192.168.232.166");
        factory.setPort(5672);

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();

        channel.queueDeclare("hello_queue",true,false,false,null);

        //接收队列中的消息

        DefaultConsumer consumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag: 消费者的标签
             * @param envelope : 设置 拿到你的交换机 路由key等信息
             * @param properties: 消息的属性对象
             * @param body: 消息的内容
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("接收的内容:"+new String(body));
                System.out.println("消费者的标志:"+consumerTag);
                System.out.println("交换机名称:"+envelope.getExchange());
                System.out.println("路由key标志:"+envelope.getRoutingKey());
                System.out.println("消息属性:"+properties);

            }
        };

        /**
         * String queue, 队列名
         * boolean autoAck,是否自动确认。 当rabbitmq把消息发送给消费后,消费端自动确认消息。
         * Consumer callback:回调。 当rabbitmq队列中存在消息 则触发该回调
         */
        channel.basicConsume("hello_queue",true,consumer);

        //不能关闭connection和channel

    }

}

6.2. WorkQueues (working mode)

Work Queues : Compared with the simple mode of the entry program, there is one or more consumers, and multiple consumers jointly consume messages in the same queue. Application scenario : When the task is too heavy or there are many tasks, using the work queue can improve the speed of task processing.

 Producer:

package work;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


/**
 * @program: qy-rabbitmq
 * @description: 工作模式生产者
 * @author:
 * @create: 2023-07-12 17:11
 **/
public class WorkProduct {
    public static void main(String[] args) throws Exception{
        //创建连接工厂并设置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        //设置rabbitmq服务的地址,默认localhost
        factory.setHost("192.168.232.166");
        //设置rabbitmq的端口号 AMQP端口
        factory.setPort(5672);
        //设置账号 默认guest
        factory.setUsername("lx");
        //设置密码 默认guest
        factory.setPassword("lx");
        //设置虚拟机 默认 /
        factory.setVirtualHost("/lx");

        //获取连接对象
        Connection connection = factory.newConnection();
        //获取channel对象
        Channel channel = connection.createChannel();

        //创建队列
        /*
        *String queue, 队列的名称. 如果该名称不存在 则创建  如果存在则不创建
        * boolean durable, 该对象是否持久化  当rabbitmq重启后 队列就会消失
        *  boolean exclusive, 该队列是否被一个消费者独占
        * boolean autoDelete,当没有消费者时,该队列是否被自动删除
        * Map<String, Object> arguments: 额外参数的设置
        * */
        //存在该队列则不会创建
        channel.queueDeclare("work_queue",true,false,false,null);

        //发送消息
      /*  String exchange, 交换机的名称 简单模式没有交换机使用""表示采用默认交换机
        String routingKey, 路由标识  如果是简单模式起名为队列的名称
        BasicProperties props, 消息的属性设置。 设置为null
        byte[] body: 消息的内容*/
         for (int i = 0; i < 20; i++) {
            String msg = "hello work rabbitmq------------";
            channel.basicPublish("","work_queue",null,msg.getBytes());
        }
        //关闭资源
        channel.close();
        connection.close();
    }

}

Consumer × 2 (one is written below):

package work;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @program: qy-rabbitmq
 * @description: 工作模式消费者
 * @author: 
 * @create: 2023-07-12 18:15
 **/
public class WorkConsumer {
    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setVirtualHost("/lx");
        factory.setUsername("lx");
        factory.setPassword("lx");
        factory.setHost("192.168.232.166");
        factory.setPort(5672);

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();


        //接收队列中的消息

        DefaultConsumer consumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag: 消费者的标签
             * @param envelope : 设置 拿到你的交换机 路由key等信息
             * @param properties: 消息的属性对象
             * @param body: 消息的内容
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("接收的内容:"+new String(body));
            }
        };

        /**
         * String queue, 队列名
         * boolean autoAck,是否自动确认。 当rabbitmq把消息发送给消费后,消费端自动确认消息。
         * Consumer callback:回调。 当rabbitmq队列中存在消息 则触发该回调
         */
        channel.basicConsume("work_queue",true,consumer);

        //不能关闭connection和channel

    }

}

Summary: If there are multiple consumers in a queue, the relationship between consumers for the same message is a competitive relationship.

Work Queues When the task is too heavy or there are many tasks, using the work queue can improve the speed of task processing. For example: if multiple SMS services are deployed, only one node needs to send it successfully.

6.3. Publish/Subscribe (publish and subscribe mode)

In the subscription model, there is an additional Exchange role, and the process changes slightly:

  • P: Producer, that is, the program that wants to send messages, but no longer sends them to the queue, but to X (switch)

  • C: The consumer, the receiver of the message, will always wait for the message to arrive.

  • Queue: message queue, receiving messages and caching messages

  • Exchange: Switch (X). On the one hand, messages sent by producers are received. On the other hand, knowing how to handle the message, such as submitting it to a special queue, submitting it to all queues, or discarding the message. How to do this depends on the type of Exchange. There are three common types of Exchange:

    1. Fanout: Broadcast, delivering messages to all queues bound to the switch

    2. Direct: Directed, the message is delivered to the queue that matches the specified routing key.

    3. Topic: Wildcard, hand the message to the queue that matches the routing pattern (routing pattern)

Exchange (switch) is only responsible for forwarding messages and does not have the ability to store messages. Therefore, if there is no queue bound to Exchange, or there is no queue that conforms to the routing rules, the message will be lost!

 Producer:

package publish;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


/**
 * @program: qy-rabbitmq
 * @description: 发布订阅模式生产者
 * @author: 
 * @create: 2023-07-12 17:11
 **/
public class PublishProduct {
    public static void main(String[] args) throws Exception{
        //创建连接工厂并设置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        //设置rabbitmq服务的地址,默认localhost
        factory.setHost("192.168.232.166");
        //设置rabbitmq的端口号 AMQP端口
        factory.setPort(5672);
        //设置账号 默认guest
        factory.setUsername("lx");
        //设置密码 默认guest
        factory.setPassword("lx");
        //设置虚拟机 默认 /
        factory.setVirtualHost("/lx");

        //获取连接对象
        Connection connection = factory.newConnection();
        //获取channel对象
        Channel channel = connection.createChannel();

        //创建交换机
        /**
         * String exchange, 交换机的名称 如果不存在则创建 存在则不创建
         * BuiltinExchangeType type, 交换机的类型
         * boolean durable: 是否持久化。
         */
        channel.exchangeDeclare("publish_exchange", BuiltinExchangeType.FANOUT,true);

        //创建队列
        //存在该队列则不会创建
        channel.queueDeclare("publish_queue01",true,false,false,null);
        channel.queueDeclare("publish_queue02",true,false,false,null);

        //队列和交换机绑定
        /**
         * String queue,
         * String exchange,
         * String routingKey: 发布订阅模式 没有routingkey 则写为”“
         */
        channel.queueBind("publish_queue01","publish_exchange","");
        channel.queueBind("publish_queue02","publish_exchange","");


        //发送消息
            String msg = "发布订阅模式广播";
            channel.basicPublish("publish_exchange","",null,msg.getBytes());

        //关闭资源
        channel.close();
        connection.close();
    }

}

Consumer × 2 (one is written below):

package publish;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @program: qy-rabbitmq
 * @description: 发布订阅模式消费者
 * @author: 
 * @create: 2023-07-12 18:15
 **/
public class PublishConsumer01 {
    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setVirtualHost("/lx");
        factory.setUsername("lx");
        factory.setPassword("lx");
        factory.setHost("192.168.232.166");
        factory.setPort(5672);

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();


        //接收队列中的消息

        DefaultConsumer consumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag: 消费者的标签
             * @param envelope : 设置 拿到你的交换机 路由key等信息
             * @param properties: 消息的属性对象
             * @param body: 消息的内容
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("接收的内容:"+new String(body));
            }
        };

        /**
         * String queue, 队列名
         * boolean autoAck,是否自动确认。 当rabbitmq把消息发送给消费后,消费端自动确认消息。
         * Consumer callback:回调。 当rabbitmq队列中存在消息 则触发该回调
         */
        channel.basicConsume("publish_queue01",true,consumer);

        //不能关闭connection和channel

    }

}
  1. The switch needs to be bound to the queue. After binding, a message can be received by multiple consumers.

  2. The difference between publish and subscribe mode and work queue mode:

    • The work queue mode does not need to define a switch, while the publish/subscribe mode requires a switch to be defined.

    • The producer of the publish/subscribe model sends messages to the switch, and the producer of the work queue model sends messages to the queue (the bottom layer uses the default switch)

    • The publish/subscribe mode requires setting the binding between the queue and the switch. The work queue mode does not need to be set. In fact, the work queue mode will bind the queue to the default switch.

6.4. Routing (routing mode)

  • The binding between the queue and the switch cannot be done arbitrarily, but a RoutingKey must be specified.

  • When sending a message to Exchange, the sender of the message must also specify the RoutingKey of the message.

  • Exchange no longer delivers messages to each bound queue, but makes judgments based on the routing key of the message. Only when the routing key of the queue is completely consistent with the routing key of the message will the message be received.

  • P: Producer, sends messages to Exchange. When sending messages, a routing key will be specified.

  • X: Exchange (switch), receives the message from the producer, and then delivers the message to the queue that exactly matches the routing key

  • C1: Consumer, whose queue specifies messages that require the routing key to be error.

  • C2: Consumer, whose queue specifies messages that require routing keys of info, error, and warning.

Producer:

package routing;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


/**
 * @program: qy-rabbitmq
 * @description: 路由模式生产者
 * @author: 
 * @create: 2023-07-12 17:11
 **/
public class RouterProduct {
    public static void main(String[] args) throws Exception{
        //创建连接工厂并设置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        //设置rabbitmq服务的地址,默认localhost
        factory.setHost("192.168.232.166");
        //设置rabbitmq的端口号 AMQP端口
        factory.setPort(5672);
        //设置账号 默认guest
        factory.setUsername("lx");
        //设置密码 默认guest
        factory.setPassword("lx");
        //设置虚拟机 默认 /
        factory.setVirtualHost("/lx");

        //获取连接对象
        Connection connection = factory.newConnection();
        //获取channel对象
        Channel channel = connection.createChannel();

        channel.exchangeDeclare("router_exchange", BuiltinExchangeType.DIRECT,true);

        //创建队列
        //存在该队列则不会创建
        channel.queueDeclare("router_queue01",true,false,false,null);
        channel.queueDeclare("router_queue02",true,false,false,null);

        //队列和交换机绑定
        channel.queueBind("router_queue01","publish_exchange","");
        channel.queueBind("router_queue02","publish_exchange","");

        channel.queueBind("router_queue01","router_exchange","error");
        channel.queueBind("router_queue02","router_exchange","error");

        //发送消息
            String msg = "路由模式";
            channel.basicPublish("router_exchange","error",null,msg.getBytes());

        //关闭资源
        channel.close();
        connection.close();
    }

}

 Consumer × 2 (one is written below):

package routing;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @program: qy-rabbitmq
 * @description: 路由模式消费者
 * @author: 
 * @create: 2023-07-12 18:15
 **/
public class RouterConsumer01 {
    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setVirtualHost("/lx");
        factory.setUsername("lx");
        factory.setPassword("lx");
        factory.setHost("192.168.232.166");
        factory.setPort(5672);

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();

        //接收队列中的消息
        DefaultConsumer consumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag: 消费者的标签
             * @param envelope : 设置 拿到你的交换机 路由key等信息
             * @param properties: 消息的属性对象
             * @param body: 消息的内容
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("接收的内容:"+new String(body));
            }
        };

        /**
         * String queue, 队列名
         * boolean autoAck,是否自动确认。 当rabbitmq把消息发送给消费后,消费端自动确认消息。
         * Consumer callback:回调。 当rabbitmq队列中存在消息 则触发该回调
         */
        channel.basicConsume("router_queue01",true,consumer);


    }

}

summary:

Routing mode requires the queue to specify a routing key when binding to the switch, and the message will be forwarded to the queue that matches the routing key.

6.5. Topics (theme mode)

  • Compared with Direct, Topic type can route messages to different queues based on RoutingKey. It's just that the Topic type Exchange allows the queue to use wildcards when binding the Routing key!

  • Routingkey generally consists of one or more words, separated by ".", for example: item.insert

  • Wildcard rules: # matches one or more words, * matches exactly one word, for example: item.# can match item.insert.abc or item.insert, item.* can only match item.insert

The matching mechanism is as shown below:

 

 Producer:

package topic;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


/**
 * @program: qy-rabbitmq
 * @description: 主题模式生产者
 * @author: 
 * @create: 2023-07-12 17:11
 **/
public class TopicProduct {
    public static void main(String[] args) throws Exception{
        //创建连接工厂并设置连接信息
        ConnectionFactory factory = new ConnectionFactory();
        //设置rabbitmq服务的地址,默认localhost
        factory.setHost("192.168.232.166");
        //设置rabbitmq的端口号 AMQP端口
        factory.setPort(5672);
        //设置账号 默认guest
        factory.setUsername("lx");
        //设置密码 默认guest
        factory.setPassword("lx");
        //设置虚拟机 默认 /
        factory.setVirtualHost("/lx");

        //获取连接对象
        Connection connection = factory.newConnection();
        //获取channel对象
        Channel channel = connection.createChannel();

        channel.exchangeDeclare("topic_exchange", BuiltinExchangeType.TOPIC,true);

        //创建队列
        //存在该队列则不会创建
        channel.queueDeclare("topic_queue01",true,false,false,null);
        channel.queueDeclare("topic_queue02",true,false,false,null);

        //队列和交换机绑定
        channel.queueBind("topic_queue01","topic_exchange","*.orange.*");
        channel.queueBind("topic_queue02","topic_exchange","*.*.rabbit");
        channel.queueBind("topic_queue02","topic_exchange","lazy.#");

        //发送消息
            String msg = "主题模式";
            channel.basicPublish("topic_exchange","lazy.orange.lx",null,msg.getBytes());

        //关闭资源
        channel.close();
        connection.close();
    }

}

Consumer × 2 (one is written below):

package topic;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @program: qy-rabbitmq
 * @description: 主题模式消费者
 * @author: 
 * @create: 2023-07-12 18:15
 **/
public class TopicConsumer01 {
    public static void main(String[] args) throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setVirtualHost("/lx");
        factory.setUsername("lx");
        factory.setPassword("lx");
        factory.setHost("192.168.232.166");
        factory.setPort(5672);

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();

        //接收队列中的消息
        DefaultConsumer consumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag: 消费者的标签
             * @param envelope : 设置 拿到你的交换机 路由key等信息
             * @param properties: 消息的属性对象
             * @param body: 消息的内容
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("接收的内容:"+new String(body));
            }
        };

        /**
         * String queue, 队列名
         * boolean autoAck,是否自动确认。 当rabbitmq把消息发送给消费后,消费端自动确认消息。
         * Consumer callback:回调。 当rabbitmq队列中存在消息 则触发该回调
         */
        channel.basicConsume("topic_queue01",true,consumer);


    }

}

Topic topic mode can realize the functions of Pub/Sub publishing and subscription mode and Routing routing mode, but Topic can use wildcards when configuring routing key, which is more flexible.

Guess you like

Origin blog.csdn.net/weixin_54065960/article/details/131684239