Common working mode of RabbitMQ + integration of springboot

Table of contents

1. Related concepts of MQ

1.1 What is MQ message middleware

1.2 Why use MQ

(1) Application decoupling

(2) Asynchronous speed up  

(3) Cut peaks and fill valleys

1.3 Disadvantages of using MQ

1.4 Common MQ components

2. Overview of RabbitMQ

2.1 The concept of RabbitMQ

2.2 The principle of RabbitMQ

2.3 Install RabbitMQ

3. Working mode of RabbitMQ

3.1 simple (simple mode)

3.2 Work queues (working mode)

3.3.Publish/Subscribe (publish subscription mode)

3.4.Routing (routing mode)

3.5.Topics (theme mode)

4.springboot integrates RabbitMQ

4.1. Producer

4.2. Consumer

4.3. Create switches and queues through code


1. Related concepts of MQ

1.1 What is MQ message middleware

The full name of MQ is Message Queue (message queue), which is a container for storing messages during message transmission. It is a method of communication between applications and applications.

1.2 Why use MQ

In the project, some time-consuming operations that do not require immediate return can be extracted and processed asynchronously , and this asynchronous processing method greatly saves the request response time of the server, thereby improving the throughput of the system .

MQ is summarized in three benefits:

(1) Application decoupling

Taking e-commerce applications as an example, there are order systems, inventory systems, logistics systems, and payment systems in the applications. After the user creates an order, if any of the subsystems fails, the order placement operation will be abnormal if the coupling calls the inventory system, logistics system, and payment system. When it is converted to a method based on message queues, the problems of inter-system calls will be greatly reduced. For example, the 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, it is enough to continue processing the order information, and the intermediate users will not feel the failure of the logistics system, which improves the availability of the system.

 

(2) Asynchronous speed up  

The time it takes to complete the order above is: 20 + 300 + 300 + 300 = 920ms. After the user clicks the order button, it takes 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)

(3) Cut peaks and fill valleys

For example, if the order system can process a maximum of 1,000 orders, this processing capacity is more than enough for placing orders during normal hours. During normal hours, we can return the results after placing an order within one second. However, during the peak period, if there are 2,000 orders placed, the operating system cannot handle them, and it can only limit the order to not allow users to place orders after more than 1,000 orders. Using the message queue as a buffer, we can cancel this restriction and divide the orders placed within one second into a period of time for processing. At this time, some users may not receive the successful operation of placing an order until more than ten seconds after placing an order, but they are not able to place an order. Single experience is better. To put it simply: even in the case of a sharp increase in visits, the application still cannot stop. For example, there are many people placing orders on "Double Eleven", but the Taobao application still needs to run, so you can use the message middleware to adopt the queue Form Reduces Stress of Unannounced Visits

After using MQ, limit the speed of consuming messages to 1000. In this way, the data generated during the peak period will inevitably be backlogged in MQ, and the peak will be "cut" off, but because of the backlog of messages, a period of time after the peak period Within a certain period of time, the speed of consuming news will still be maintained at 1000 until the backlog of news is consumed, which is called "filling the valley".

After using MQ, the system stability can be improved

1.3 Disadvantages of using MQ

  • The more external dependencies the system introduces, the worse the system stability will be. Once MQ goes down, it will affect the business. How to ensure the high availability of MQ?
  • Increased system complexity The addition of MQ has greatly increased the complexity of the system. In the past, there were synchronous remote calls 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 to ensure the order of message delivery?
  • Consistency problem System A finishes processing the business and sends message data to systems B, C, and D through MQ. If systems B and C process successfully, system D fails. How to ensure the consistency of message data processing?

1.4 Common MQ components

At present, there are many MQ products in the industry, such as RabbitMQ, RocketMQ, ActiveMQ, Kafka, ZeroMQ, MetaMq, etc., and there are also cases of directly using Redis as a message queue. Own needs and MQ product features

2. Overview of RabbitMQ

2.1 The concept of RabbitMQ

  • Released in 2007, it is a reusable enterprise messaging system based on AMQP (Advanced Message Queuing Protocol), and is one of the most mainstream messaging middleware at present.
  • RabbitMQ is an open source implementation of AMQP (Advanced Message Queue Advanced Message Queuing Protocol) developed by erlang. Due to the high concurrency of the erlang language, it has better performance. It is essentially a queue. FIFO is 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 in the courier station, and the courier will eventually deliver your courier to the recipient. According to this logic, RabbitMQ is a courier Station, a courier will deliver the express for you. The main difference between RabbitMQ and the express station is that it does not process express mail but receives, stores and forwards message data.

2.2 The principle of RabbitMQ

Glossary:

  • Broker : The application for receiving and distributing messages, RabbitMQ Server is Message Broker
  • Virtual host : Designed for multi-tenancy and security factors, 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 an exchange/queue in his own vhost, etc.
  • Connection : TCP connection between publisher/consumer and broker
  • Channel : If a Connection is established every time RabbitMQ is accessed, the overhead of establishing a TCP Connection when the message volume is large will be huge and the efficiency will be low. Channel is a logical connection established inside the connection. If the application supports multi-threading, usually each thread creates a separate channel for communication. AMQP method includes the channel id to help the client and message broker identify the channel, so the channels are completely isolated of. As a lightweight Connection, Channel greatly reduces the overhead of the operating system to establish a TCP connection.
  • Exchange : The message arrives at the first stop of the broker, according to the distribution rules, 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)
  • Queue : The message is finally sent here and waits for the consumer to pick it up
  • Binding : virtual connection between exchange and queue, binding can contain routing key. Binding information is stored in the query table in the exchange for the basis of message distribution

2.3 Install RabbitMQ

Installation details------>Virtual machine installation RabbitMQ

3. Working mode of RabbitMQ

RabbitMQ provides 6 working modes: simple mode, work queues, Publish/Subscribe publishing and subscribing mode, Routing routing mode, Topics topic mode, RPC remote calling mode (remote calling, not quite MQ; no introduction for now). Introduction to the corresponding mode on the official website: RabbitMQ Tutorials — RabbitMQ

3.1 simple (simple mode)

In the model above, there are the following concepts:

P: Producer, that is, the program to send the message

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

queue: message queue , the red part in the figure. Similar to a mailbox, messages can be cached; producers post messages to it, and consumers take messages from it

Demo:

create project

 increase dependence

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

 producer:

package com.wqg.producer;

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


/**
 * @ fileName:SimpleProducer
 * @ description:简单模式-生产者
 * @ author:wqg
 * @ createTime:2023/7/12 16:26
 */
public class SimpleProducer {
    public static void main(String[] args) throws Exception {
        //创建连接工厂对象并设置连接信息   -----获取连接对象(指定rabbitMQ服务端的信息)
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //rabbitMQ服务端的地址  默认localhost
        connectionFactory.setHost("192.168.75.129");
        //设置端口号
        connectionFactory.setPort(5672);
        //设置账号   默认guest
        connectionFactory.setUsername("guest");
        //设置密码   默认guest
        connectionFactory.setPassword("guest");
        //设置虚拟主机   默认/
        connectionFactory.setVirtualHost("/");

        //获取连接对象
        Connection connection = connectionFactory.newConnection();

        //获取Channel信道对象
        Channel channel = connection.createChannel();

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

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

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

consumer:

3.2  Work queues (working mode)

 Work Queues : Compared with the simple mode of the starter program, there are one or more consumers, and multiple consumers consume messages in the same queue together.

Application scenario : Using the work queue can improve the speed of task processing when the task is too heavy or there are many tasks

producer:

package com.wqg.producer;

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


/**
 * @ fileName:SimpleProducer
 * @ description:工作模式-生产者
 * @ author:wqg
 * @ createTime:2023/7/12 16:26
 */
public class WorkProducer {
    public static void main(String[] args) throws Exception {
        //创建连接工厂对象并设置连接信息   -----获取连接对象(指定rabbitMQ服务端的信息)
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //rabbitMQ服务端的地址  默认localhost
        connectionFactory.setHost("192.168.75.129");
        //设置端口号
        connectionFactory.setPort(5672);
        //设置账号   默认guest
        connectionFactory.setUsername("guest");
        //设置密码   默认guest
        connectionFactory.setPassword("guest");
        //设置虚拟主机   默认/
        connectionFactory.setVirtualHost("/");

        //获取连接对象
        Connection connection = connectionFactory.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<10; i++){
            String msg = "Hello RabbitMQ~~~工作模式";
            channel.basicPublish("", "Work-Queue", null, msg.getBytes());
        }


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

consumer:

package com.wqg.consumer;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @ fileName:SimpleConsumer
 * @ description:工作模式-消费者
 * @ author:WQG
 * @ createTime:2023/7/12 16:25
 */
public class WorkConsumer01 {
    public static void main(String[] args) throws Exception {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.75.129");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        //channel.queueDeclare("Work-queue", true, false, false, null);

        //接受队列中的信息
        Consumer 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);
    }
}

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

Work Queues The use of work queues can improve the speed of task processing when tasks are too heavy or there are many tasks.

For example, if there are multiple SMS service deployments, only one node needs to send them successfully.

3.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 to send the message, but no longer sent to the queue, but to X (exchange)

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

  • Queue: message queue, receiving messages, buffering messages

  • Exchange: Exchange (X). On the one hand, receive messages sent by producers. On the other hand, knowing how to process the message, such as delivering it to a particular queue, delivering it to all queues, or discarding the message. How it works depends on the type of Exchange. There are three common types of Exchange:

    1. Fanout: Broadcast, hand over the message to all queues bound to the exchange

    2. Direct: directional, deliver the message to the queue that matches the specified routing key

    3. Topic: wildcard, send the message to the queue that matches the routing pattern (routing pattern)

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

producer:

package com.wqg.producer;

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


/**
 * @ fileName:SimpleProducer
 * @ description:发布订阅模式-生产者
 * @ author:wqg
 * @ createTime:2023/7/12 16:26
 */
public class PublishProducer {
    public static void main(String[] args) throws Exception {
        //创建连接工厂对象并设置连接信息   -----获取连接对象(指定rabbitMQ服务端的信息)
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //rabbitMQ服务端的地址  默认localhost
        connectionFactory.setHost("192.168.75.129");
        //设置端口号
        connectionFactory.setPort(5672);
        //设置账号   默认guest
        connectionFactory.setUsername("guest");
        //设置密码   默认guest
        connectionFactory.setPassword("guest");
        //设置虚拟主机   默认/
        connectionFactory.setVirtualHost("/");

        //获取连接对象
        Connection connection = connectionFactory.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 = "Hello RabbitMQ~~~发布订阅模式";
        channel.basicPublish("Publish-exchange","", null, msg.getBytes());


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

 consumer:

package com.wqg.consumer;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @ fileName:SimpleConsumer
 * @ description:发布订阅模式-消费者
 * @ author:WQG
 * @ createTime:2023/7/12 16:25
 */
public class PublishConsumer {
    public static void main(String[] args) throws Exception {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.75.129");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        //channel.queueDeclare("Work-queue", true, false, false, null);

        //接受队列中的信息
        Consumer 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队列中存在消息 则触发该回调
         */
        //Publish-Queue02和Publish-Queue01只有一个里面有数据
        channel.basicConsume("Publish-Queue02", true,consumer);
    }
}
  1. The switch needs to be bound to the queue. After binding, a message can be received by multiple consumers.

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

  • The work queue mode does not need to define a switch, while the publish/subscribe mode needs to define a switch
  • The production side of the publish/subscribe mode is to send messages to the switch, and the production side of the work queue mode is to send messages to the queue (the bottom layer uses the default switch)
  • The publish/subscribe mode needs to set the binding of the queue and the switch, and the work queue mode does not need to be set. In fact, the work queue mode will bind the queue to the default switch

3.4. Routing (routing mode)

  • The binding between the queue and the switch cannot be arbitrary binding, but a RoutingKey (routing key) must be specified

  • The sender of the message must also specify the RoutingKey of the message when sending the message to Exchange

  • Exchange no longer delivers messages to each bound queue, but judges based on the Routing Key of the message. Only when the Routing Key of the queue is exactly the same as the Routing Key of the message, can the message be received

  • P: Producer, send a message to Exchange, when sending a message, a routing key will be specified

  • X: Exchange (exchange), receive the producer's message, and then deliver the message to the queue that exactly matches the routing key

  • C1: The consumer whose queue specifies a message whose routing key is error

  • C2: Consumers, whose queues specify messages whose routing keys are info, error, and warning

producer:

package com.wqg.producer;

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


/**
 * @ fileName:SimpleProducer
 * @ description:路由模式-生产者
 * @ author:wqg
 * @ createTime:2023/7/12 16:26
 */
public class RouterProducer {
    public static void main(String[] args) throws Exception {
        //创建连接工厂对象并设置连接信息   -----获取连接对象(指定rabbitMQ服务端的信息)
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //rabbitMQ服务端的地址  默认localhost
        connectionFactory.setHost("192.168.75.129");
        //设置端口号
        connectionFactory.setPort(5672);
        //设置账号   默认guest
        connectionFactory.setUsername("guest");
        //设置密码   默认guest
        connectionFactory.setPassword("guest");
        //设置虚拟主机   默认/
        connectionFactory.setVirtualHost("/");

        //获取连接对象
        Connection connection = connectionFactory.newConnection();

        //获取Channel信道对象
        Channel channel = connection.createChannel();

        //创建交换机
        channel.exchangeDeclare("Router-exchange", BuiltinExchangeType.DIRECT,true);

        //创建队列
        channel.queueDeclare("Router-queue001",true,false,false,null);
        channel.queueDeclare("Router-queue002",true,false,false,null);

        //队列和交换机绑定
        channel.queueBind("Router-queue001","Router-exchange","error");
        channel.queueBind("Router-queue002","Router-exchange","error");
        channel.queueBind("Router-queue002","Router-exchange","info");
        channel.queueBind("Router-queue002","Router-exchange","warning");
        String msg = "Hello RabbitMQ~~~路由模式";
        channel.basicPublish("Router-exchange","info",null,msg.getBytes());

        channel.close();
        connectionFactory.clone();
    }
}

consumer:

package com.wqg.consumer;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @ fileName:SimpleConsumer
 * @ description:路由模式-消费者
 * @ author:WQG
 * @ createTime:2023/7/12 16:25
 */
public class RouterConsumer {
    public static void main(String[] args) throws Exception {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.75.129");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        //channel.queueDeclare("Work-queue", true, false, false, null);

        //接受队列中的信息
        Consumer 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-queue002", true,consumer);
    }
}

Summarize:

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

3.5.Topics (theme mode)

  • Compared with Direct, Topic type can route messages to different queues according to 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

producer:  

package com.wqg.producer;

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


/**
 * @ fileName:SimpleProducer
 * @ description:主题模式-生产者
 * @ author:wqg
 * @ createTime:2023/7/12 16:26
 */
public class TopicsProducer {
    public static void main(String[] args) throws Exception {
        //创建连接工厂对象并设置连接信息   -----获取连接对象(指定rabbitMQ服务端的信息)
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //rabbitMQ服务端的地址  默认localhost
        connectionFactory.setHost("192.168.75.129");
        //设置端口号
        connectionFactory.setPort(5672);
        //设置账号   默认guest
        connectionFactory.setUsername("guest");
        //设置密码   默认guest
        connectionFactory.setPassword("guest");
        //设置虚拟主机   默认/
        connectionFactory.setVirtualHost("/");

        //获取连接对象
        Connection connection = connectionFactory.newConnection();

        //获取Channel信道对象
        Channel channel = connection.createChannel();

        //创建交换机
        channel.exchangeDeclare("Topics-exchange", BuiltinExchangeType.TOPIC,true);

        //创建队列
        channel.queueDeclare("Topics-queue001",true,false,false,null);
        channel.queueDeclare("Topics-queue002",true,false,false,null);

        //队列和交换机绑定
        channel.queueBind("Topics-queue001","Topics-exchange","*.orange.*");
        channel.queueBind("Topics-queue002","Topics-exchange","*.*.rabbit");
        channel.queueBind("Topics-queue002","Topics-exchange","lazy.#");
        String msg = "Hello RabbitMQ~~~主题模式";
        channel.basicPublish("Topics-exchange","lazy.rabbit.orange",null,msg.getBytes());

        channel.close();
        connectionFactory.clone();
    }
}

consumer:

package com.wqg.consumer;

import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @ fileName:SimpleConsumer
 * @ description:路由模式-消费者
 * @ author:WQG
 * @ createTime:2023/7/12 16:25
 */
public class TopicsConsumer {
    public static void main(String[] args) throws Exception {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.75.129");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        //channel.queueDeclare("Work-queue", true, false, false, null);

        //接受队列中的信息
        Consumer 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("Topics-queue002", true,consumer);
    }
}

Topic topic mode can implement the functions of Pub/Sub publishing and subscription mode and Routing routing mode,

It's just that the topic can use wildcards when configuring the routing key, which is more flexible.

4.springboot integrates RabbitMQ

4.1. Producer

Create a springboot project----producer
(1) Introduce the dependency of rabbitmq integration
 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
(2) Add rabbit service information to the configuration file
#rabbitmq的配置
spring.rabbitmq.host=192.168.75.129
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
(3) Call the method of sending messages in RabbitTemplate
@SpringBootTest
class RabbitmqSpringbootApplicationTests {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    void contextLoads() {
        rabbitTemplate.convertAndSend("Topics-exchange","lazy.aaa","Hello RabbitMQ...");
    }

}

4.2. Consumer

Create a springboot project----consumer

(1) Introduce the dependency of rabbitmq integration ------ same as above

(2) Add the rabbit service information to the configuration file ------ same as above

(3) Create a class --- create a listening method @RabbitListener
@Component
public class MyListener {

    //queues:表示你监听的队列名
    @RabbitListener(queues = {"Topics-queue002"})
    public void h(Message message){
        //把监听到的消息封装到Message类对象中
        byte[] body = message.getBody();
        System.out.println("消息内容==="+new String(body));
    }
}

4.3. Create switches and queues through code

package com.wqg.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @ fileName:RabbitConfig
 * @ description:
 * @ author:wqg
 * @ createTime:2023/7/12 19:41
 */
@Configuration
public class RabbitConfig {
    //定义了一个名为EXCHANGE_NAME的常量,用于表示交换器的名称
    public static final String EXCHANGE_NAME = "Topics-queue002";

    @Bean
    public Exchange exchange() {
        // 创建一个Topic类型的Exchange,名称为EXCHANGE_NAME,持久化
        Exchange topic_exchange02 = ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
        return topic_exchange02;
    }

    @Bean
    public Queue queue() {
        // 创建一个持久化的队列,名称为"Topics-queue003"
        Queue topic_queue03 = QueueBuilder.durable("Topics-queue003").build();
        return topic_queue03;
    }

    @Bean
    public Binding binding() {
        // 创建一个绑定关系,将队列绑定到Exchange上,并指定routing key为"qy165.#",不使用任何参数
        Binding noargs = BindingBuilder.bind(queue()).to(exchange()).with("qy165.#").noargs();
        return noargs;
    }

    //如果交换机要绑定多个队列 需要再写一个bind方法

}

Guess you like

Origin blog.csdn.net/WQGuang/article/details/131687882