Introducción detallada y uso de varios modos comunes de RabbitMQ --- práctica

Introducción detallada y uso de varios modos comunes de RabbitMQ - práctica

Sitio web oficial: RabbitMQ

Documentación oficial: Introducción a cada modo

RabbitMQ no se presentará en detalle. Los siguientes son los principios y operaciones prácticas de cada modo:

1. Configuración de la instalación

查看mq镜像: docker search rabbitmq:management
下载mq镜像: docker pull rabbitmq:management
安装镜像:docker run -d --name rabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin -p 15672:15672 -p 5672:5672 -p 25672:25672 -p 61613:61613 -p 1883:1883 rabbitmq:management

说明
5672:默认的客户端连接的端口
15672:默认的web管理界面的端口
 命令中的【RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin】是web管理平台的用户名和密码
【 -p 15672:15672】 是控制平台docker映射到系统的对应端口
【 -p 5672:5672】 是应用程序的访问端口

访问地址
http://ip:15672

Si es un servidor Linux, primero abra el puerto del servidor, como Alibaba Cloud, primero configure el grupo de seguridad:

imagen-20210926180156983

Añadir:

imagen-20210926180312617

iniciar la instalación:

Preguntardocker search rabbitmq:management

imagen-20210926175821524

descargardocker search rabbitmq:management

Instalardocker run -d --name rabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin -p 15672:15672 -p 5672:5672 -p 25672:25672 -p 61613:61613 -p 1883:1883 rabbitmq:management

imagen-20210926175859729

Instalación exitosa

imagen-20210926180008591

Dirección de acceso:
http://tu ip:15672

2. prueba

Primero crea una clase de conexión:

package boot.spring.controller;

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

/**
 * @description
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class ConnectionUtil {
    
    
    /**
     * 获取连接
     * @return Connection
     * @throws Exception
     */
    public static Connection getConnection() throws Exception {
    
    
        //定义连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("你的ip");
        factory.setPort(5672);
        //设置vhost
        factory.setVirtualHost("/");
        factory.setUsername("admin");
        factory.setPassword("admin");
        //通过工厂获取连接
        Connection connection = factory.newConnection();
        return connection;
    }
}

2.1 Modo sencillo

Un productor, un consumidor.

Esquemático:imagen-20210927094435976

enviar:

package boot.spring.controller.easy;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

/**
 * @description 1.简单模式:一个生产者一个消费者
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class TestSend {
    
    
    public final static String QUEUE_NAME = "test-queue";
    //创建队列,发送消息
    public static void main(String[] args) throws Exception {
    
    
        //获取连接
        Connection connection = ConnectionUtil.getConnection();
        //创建通道
        Channel channel = connection.createChannel();
        //声明创建队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //消息内容
        String message = "Hello World!";
        channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
        System.out.println("发送消息:"+message);
        //关闭连接和通道
        channel.close();
        connection.close();
    }

}

imagen-20210926185732305

Un mensaje producido no se consume:

imagen-20210926185843146

tomar el control:

package boot.spring.controller.easy;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 简单模式一个生产者一个消费者
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class TestResive {
    
    
    //消费者消费消息
    public static void main(String[] args) throws Exception {
    
    
        //获取连接和通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明通道
        channel.queueDeclare(TestSend.QUEUE_NAME,false,false,false,null);
        //定义消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //监听队列
        channel.basicConsume(TestSend.QUEUE_NAME,true,consumer);

        while(true){
    
    
            //这个方法会阻塞住,直到获取到消息
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("接收到消息:"+message);
        }
    }
}

imagen-20210926185917182

ha sido consumido por:

imagen-20210926185945971

2.2 modo de trabajo

modelo de consumo competitivo

Un productor, varios consumidores, cada consumidor recibe un mensaje único y el mensaje producido se dividirá entre los consumidores.

Esquemático:imagen-20210927094551158

Para producir 100 mensajes:

package boot.spring.controller.work;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

/**
 * @description 2.work模式:一个生产者多个消费者
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class WorkSend2 {
    
    
    public final static String QUEUE_NAME = "test2";
    //消息生产者
    public static void main(String[] args) throws Exception {
    
    
        //获取连接和通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        String message = "";
        for(int i = 0; i<100; i++){
    
    
            message = "" + i;
            channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
            System.out.println("发送消息:"+message);
            Thread.sleep(i);
        }

        channel.close();
        connection.close();
    }
}

imagen-20210927095421093

Consumidor 1:

package boot.spring.controller.work;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 2.work模式:一个生产者多个消费者
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class WorkResive1 {
    
    

    //消费者1  自动模式
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(WorkSend2.QUEUE_NAME,false,false,false,null);

        //同一时刻服务器只发送一条消息给消费端
        channel.basicQos(1);

        QueueingConsumer consumer = new QueueingConsumer(channel);

        channel.basicConsume(WorkSend2.QUEUE_NAME,false,consumer);

        while(true){
    
    
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("recive1:"+message);
            Thread.sleep(100);
            //消息消费完给服务器返回确认状态,表示该消息已被消费
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        }
    }
}

Consumidor 1, consumiendo la mitad de los 100 mensajes:

imagen-20210927095602819

Consumidor 2:

package boot.spring.controller.work;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 2.work模式:一个生产者多个消费者
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class WorkResive2 {
    
    

    //消费者2  手动模式
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("test2",false,false,false,null);

        channel.basicQos(1);

        QueueingConsumer consumer = new QueueingConsumer(channel);

        channel.basicConsume("test2",true,consumer);

        while(true){
    
    
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("recive1:"+message);
            Thread.sleep(10);
            //channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        }
    }
}

El consumidor 2 consume la otra mitad de los 100 mensajes:

imagen-20210927095726835

2.3 Modo de Suscripción

Los productores envían mensajes a los intercambios y los consumidores reciben mensajes de los intercambios.

Esquemático:imagen-20210927100245937

El productor envía un mensaje al intercambio:

package boot.spring.controller.exchange;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

/**
 * @description 3.订阅者模式:一个生产者发送的消息会被多个消费者获取
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class Send {
    
    
    public static final String EXCHANGE_NAME = "test_exchange_fanout";
    //生产者,发送消息到交换机
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明交换机 fanout:交换机类型 主要有fanout,direct,topics三种
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");

        String message = "订阅模式:消息007!";
        channel.basicPublish(EXCHANGE_NAME,"",null,message.getBytes());
        System.out.println(message);
        channel.close();
        connection.close();
    }
}

Mensajes producidos:

imagen-20210927101447291

Consumidor 1:

package boot.spring.controller.exchange;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 3.订阅者模式:一个生产者发送的消息会被多个消费者获取
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class Resive1 {
    
    
    //消费者1
    public final static String QUEUE_NAME = "test_queue_exchange_1";
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机上
        channel.queueBind(QUEUE_NAME,Send.EXCHANGE_NAME,"");
        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME,true,consumer);
        while(true){
    
    
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("消费者1:"+message);
        }
    }
}

imagen-20210927101551786

Consumidor 2:

package boot.spring.controller.exchange;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 3.订阅者模式:一个生产者发送的消息会被多个消费者获取
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class Resive2 {
    
    
    //消费者2
    public final static String QUEUE_NAME = "test_queue_exchange_2";
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机上
        channel.queueBind(QUEUE_NAME,Send.EXCHANGE_NAME,"");
        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME,true,consumer);

        while(true){
    
    
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("消费者2:"+message);
        }
    }
}

imagen-20210927101633853

Se puede ver que en el modo de abonado, todos los consumidores han recibido mensajes a través del conmutador.

2.4 Modo de enrutamiento

Cuando el productor envía un mensaje a la cola, puede personalizar una clave y el consumidor puede seleccionar el mensaje correspondiente de acuerdo con la clave y obtener lo que necesita.
Nota: La clave de enrutamiento es una coincidencia exacta y solo los consumidores coincidentes pueden consumir mensajes.

Esquemático:imagen-20210927102501361

El productor produce mensajes con clave: (clave="perro")

package boot.spring.controller.rout;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

/**
 * @description 4.路由模式:发送消息到交换机并且要指定路由key
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class RoutSend {
    
    
    public static final String EXCHANGE_NAME = "test_exchange_direct";
    //生产者
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明交换机 fanout:交换机类型 主要有fanout,direct,topics三种
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");

        String message = "路由模式产生的消息!";
        channel.basicPublish(EXCHANGE_NAME,"dog",null,message.getBytes());
        System.out.println(message);
        channel.close();
        connection.close();
    }
}

imagen-20210927102827292

Consumidor 1: (clave="perro")

package boot.spring.controller.rout;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 4.路由模式:消费者将队列绑定到交换机时需要指定路由key
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class RoutResive1 {
    
    

    //消费者1
    public final static String QUEUE_NAME = "test_queue_direct_1";
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机上,并制定路由键为"dog"
        channel.queueBind(QUEUE_NAME, RoutSend.EXCHANGE_NAME,"dog");
        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME,true,consumer);
        while(true){
    
    
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("RoutResive1:"+message);
        }
    }
}

imagen-20210927103033299

Consumidor 2: (clave="gato")

package boot.spring.controller.rout;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 4.路由模式:消费者将队列绑定到交换机时需要指定路由key
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class RoutResive2 {
    
    

    //消费者2
    public final static String QUEUE_NAME = "test_queue_direct_2";
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机上,并制定路由键为"cat"
        channel.queueBind(QUEUE_NAME, RoutSend.EXCHANGE_NAME,"cat");
        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME,true,consumer);
        while(true){
    
    
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("RoutResive2:"+message);
        }
    }
}

imagen-20210927103119368

Obviamente, el consumidor 1 entendió el mensaje, pero el consumidor 2 no entendió el mensaje, porque la clave del consumidor 2 es inconsistente con la clave del productor.

2.5 Patrón comodín

El principio es similar al modo de enrutamiento, excepto que el valor clave tiene una coincidencia aproximada.

  • * (asterisco) puede reemplazar exactamente una palabra.

  • # (hash) puede reemplazar cero o más palabras

  • El intercambio de temas asigna el atributo de la clave de enrutamiento del mensaje a través de la coincidencia de patrones y hace coincidir la clave de enrutamiento con un patrón determinado. En este momento, la cola debe vincularse a un patrón. Divide la cadena de claves de enrutamiento y claves de enlace en palabras separadas por puntos. También reconoce dos caracteres comodín: el símbolo "#" y el símbolo "*". # coincide con 0 o más palabras, * coincide con una palabra. Como se muestra abajo:

    20180628164513643

Esquemático:imagen-20210927103418777

El productor produce el mensaje:

package boot.spring.controller.topic;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

/**
 * @description 5.路由模式:发送消息到交换机并且要指定通配符路由
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class TopicSend {
    
    
    //生产者
    public static final String EXCHANGE_NAME = "test_exchange_topic";

    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明交换机 topic:交换机类型
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        String message = "通配符模式产生的消息";
        channel.basicPublish(EXCHANGE_NAME,"dog.1",null,message.getBytes());
        System.out.println(message);
        channel.close();
        connection.close();
    }
}

imagen-20210927104718676

Consumidor 1:

package boot.spring.controller.topic;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 5.路由模式:消费者将队列绑定到交换机时需要指定通配符路由key
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class TopicResive1 {
    
    

    //消费者1
    public final static String QUEUE_NAME = "test_queue_topic_1";
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机上,并制定路由键匹配规则为"dog.*"
        channel.queueBind(QUEUE_NAME, TopicSend.EXCHANGE_NAME,"dog.*");
        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME,true,consumer);

        while(true){
    
    
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("TopicResive1:"+message);
        }
    }
}

imagen-20210927104759387

Consumidor 2:

package boot.spring.controller.topic;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 5.路由模式:消费者将队列绑定到交换机时需要指定通配符路由key
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class TopicResive2 {
    
    

    //消费者2
    public final static String QUEUE_NAME = "test_queue_topic_2";
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机上,并制定路由键匹配规则为"#.1"
        channel.queueBind(QUEUE_NAME, TopicSend.EXCHANGE_NAME,"#.1");
        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME,true,consumer);

        while(true){
    
    
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("TopicResive2:"+message);
        }
    }
}

imagen-20210927104900197

Consumidor 3:

package boot.spring.controller.topic;

import boot.spring.controller.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * @description 5.路由模式:消费者将队列绑定到交换机时需要指定通配符路由key
 * @AUTHER: sk
 * @DATE: 2021/9/26
 **/

public class TopicResive3 {
    
    

    //消费者3
    public final static String QUEUE_NAME = "test_queue_topic_3";
    public static void main(String[] args) throws Exception {
    
    
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机上,并制定路由键匹配规则为"cat.#"
        channel.queueBind(QUEUE_NAME, TopicSend.EXCHANGE_NAME,"cat.#");
        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(QUEUE_NAME,true,consumer);

        while(true){
    
    
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("TopicResive3:"+message);
        }
    }
}

imagen-20210927104935796

Resultado: el consumidor 1 y el consumidor 2 pueden recibir el mensaje, pero el consumidor 3 no puede recibir el mensaje.

Dirección completa del código:

dirección de Git
https://github.com/DongFangXiaoYu/springBoot-RabbitMq/tree/master

Supongo que te gusta

Origin blog.csdn.net/SHUKAI618/article/details/120505057
Recomendado
Clasificación