RabbitMq

【Docker】之安装 RabbitMQ 1、下载 RabbitMQ 镜像 下载最新版本的镜像: docker pull rabbitmq 更多版本的镜像可以访问 Docker 官网:https://hub.docker.com/_/rabbitmq?tab=tags 2、创建并运行 RabbitMQ 容器 启动命令: docker run -d -p 15672:15672 -p 5672:5672 \ -e RABBITMQ_DEFAULT_VHOST=my_vhost \ -e RABBITMQ_DEFAULT_USER=adm 阅读详情

1.RabbitMQ概念
1.1.基本概念

MQ全称为Message Queue,即消息队列. 它也是一个队列,遵循FIFO原则.

RabbitMQ是由erlang语言开发,基于AMQP(Advanced Message Queue Protocol高级消息队列协议)协议实现的消息队列,它是一种应用程序之间的通信方法,消息队列在分布式系统开 发中应用非常广泛。

1.2.RabbitMQ使用场景
  • 消峰&限流
  • 应用解耦
  • 异步处理
  • 数据分发
  • 消息通讯
  • 分布式事务
  • 排序保证&先进先出

在这里插入图片描述

1.3.常见的消息队列

ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ、Redis。

2.RabbitMQ的原理
2.1.原理图

在这里插入图片描述

2.2.执行流程
组成部分说明如下:
 Broker:消息队列服务进程,此进程包括两个部分:Exchange和Queue。
 	Exchange:消息队列交换机,按一定的规则将消息路由转发到某个队列,对消息进行过虑。
Queue:消息队列,存储消息的队列,消息到达队列并转发给指定的消费方。 
Producer:消息生产者,即生产方客户端,生产方客户端将消息发送到MQ。 
Consumer:消息消费者,即消费方客户端,接收MQ转发的消息。

 消息发布接收流程:
 -----发送消息----- 
1、生产者和Broker建立TCP连接。
2、生产者和Broker建立通道。
3、生产者通过通道消息发送给Broker,由Exchange将消息进行转发。
4、Exchange将消息转发到指定的Queue(队列) 
----接收消息-----
1、消费者和Broker建立TCP连接 
2、消费者和Broker建立通道 
3、消费者监听指定的Queue(队列)
4、当有消息到达Queue时Broker默认将消息推送给消费者。
5、消费者接收到消息。
3.安装RabbitMQ
3.1.安装erlang语音

otp_win64_20.2.exe

3.2.配置erlang的环境变量
3.3.安装RabbitMQ

rabbitmq-server-3.7.4.exe

3.4.安装RabbitMQ的可视化插件

进入mq地 安装目录的sbin目录,cmd执行 rabbitmq-plugins.bat enable rabbitmq_management

3.5.访问测试

http://localhost:15672 账号 : guest/guest

4.Rabbit的使用-helloworld

在这里插入图片描述

4.1.helloworld结构图

在这里插入图片描述

4.2.helloworld完成
4.2.1.导入依赖
<dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <!--和springboot2.0.5对应-->
            <version>5.4.1</version>
        </dependency>
4.2.2.准备连接工具类
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class ConnectionUtil {
    /**
     * 建立与RabbitMQ的连接
     * @return
     * @throws Exception
     */
    public static Connection getConnection() throws Exception {
        //定义连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //设置服务地址
        factory.setHost("127.0.0.1");
        //端口
        factory.setPort(5672);
        //设置账号信息,用户名、密码、vhost
//Virtual代表虚拟消息服务器,每个服务器相对独立
        factory.setVirtualHost("/");
        factory.setUsername("guest");
        factory.setPassword("guest");
        // 通过工程获取连接
        Connection connection = factory.newConnection();
        return connection;
    }
}
4.2.3.创建消息发送者
public class Sen {

    //队列的名字
    private static final String QUEUE_HELLO = "queue_hello";

    public static void main(String[] args) {
        Connection connection = null;
        Channel channel = null;
        try{
            //1.创建链接对象
            connection = ConnectionUtil.getConnection();

            //2.创建通道
            channel = connection.createChannel();

            //3.声明队列:队列名字 ; 持久 ;独占链接 ;不用即删除 ; 参数
            channel.queueDeclare(QUEUE_HELLO, true, false, false, null);

            //4.发送消息:交换机 ; 队列名(routingkey) ;参数 ;消息了内容
            channel.basicPublish("", QUEUE_HELLO ,null ,"我是一个hello消息".getBytes() );
            System.out.println("已经发送消息:我是一个hello消息");

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(channel != null){
                try {
                    channel.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }


    }
}
4.2.4.创建消息接受者
public class Rev {
    //队列的名字
    private static final String QUEUE_HELLO = "queue_hello";
    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            channel.queueDeclare(QUEUE_HELLO, true, false, false, null);


            Consumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {


                    //交换机
                    String exchange = envelope.getExchange();
                    System.out.println("exchange:"+exchange);
                    //路由key
                    String routingKey = envelope.getRoutingKey();
                    System.out.println("routingKey:"+routingKey);
                    //消息id
                    long deliveryTag = envelope.getDeliveryTag();
                    System.out.println("deliveryTag:"+deliveryTag);
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("收到消息:" + msg);
                    //System.out.println(1 / 0);

                    channel.basicAck(deliveryTag, false);
                }
            };
            //4.接受消息 :队列 ; 签收方式(true:自动签收)
            channel.basicConsume(QUEUE_HELLO, false,consumer);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

4.2.5.手动签收
 //4.接受消息 :队列 ; 签收方式(true:自动签收)
 channel.basicConsume(QUEUE_HELLO, false,consumer);
 
 在回调方法中
 channel.basicAck(deliveryTag, false);
5.RabbitMq-workqueues
5.1.workqueues的思想

work queues与入门程序相比,多了一个消费端,两个消费端共同消费同一个队列中的消息。

应用场景:对于任务过重或任务较多情况使用工作队列可以提高任务处理的速度。

在这里插入图片描述

5.2.workqueues代码实现
5.2.1.创建消息发送者

同 helloword一样,只是改个队列的名字

5.2.2.创建多个消息接受者

同 helloword一样,只是改个队列的名字

5.2.3.设置能者多劳

设置接受者同时只能处理一个消息

channel.basicQos(1);
6.发布订阅模型
6.1.原理图

在这里插入图片描述

解读:

1、1个生产者,多个消费者

2、每一个消费者都有自己的一个队列

3、生产者没有将消息直接发送到队列,而是发送到了交换机

4、每个队列都要绑定到交换机

5、生产者发送的消息,经过交换机到达队列,实现一个消息被多个消费者获取的目的

X(Exchanges):交换机一方面:接收生产者发送的消息。另一方面:知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。

6.2.Exchange分类
  • Fanout:广播

    将消息交给所有绑定到交换机的队列 all

  • Direct:定向

    把消息交给符合指定routing key 的队列 一堆或一个

  • Topic:通配符

    把消息交给符合routing pattern(路由模式)的队列 一堆或者一个

7.Fanout广播模式
7.1.Fanout广播模式

Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!

7.2.Fanout模式的原理

在这里插入图片描述

在广播模式下,消息发送流程是这样的:

- 1)  可以有多个消费者
- 2)  每个消费者有自己的queue(队列)
- 3)  每个队列都要绑定到Exchange(交换机)
- 4)  生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定。
- 5)  交换机把消息发送给绑定过的所有队列
- 6)  队列的消费者都能拿到消息。实现一条消息被多个消费者消费
7.3.实现Fanout模式

发送者需要声明交换机 ,不需要声明队列,发送消息的时候需要指定交换机,不需要指定routingkey接受者需要声明队列 , 需要给队列绑定交换机 ,接受者的交换机和消息发送者的交换机要一致。多个消息接受者,声明的队列的名字需要不一样,而交换机的名字需要一样。

7.3.1.消息发送者
public class Sen {

    //交换机的名字
    private static final String EXCHANGE_FANOUT = "exchange_fanout";

    public static void main(String[] args) {
        Connection connection = null;
        Channel channel = null;
        try{
            //1.创建链接对象
            connection = ConnectionUtil.getConnection();

            //2.创建通道
            channel = connection.createChannel();

            //3.声明交换机指定类型为fanout
            channel.exchangeDeclare(EXCHANGE_FANOUT, BuiltinExchangeType.FANOUT);

            //4.发送消息:交换机 ; 队列名(routingkey) ;参数 ;消息了内容
            String message = "我是一个fanout消息";

            channel.basicPublish(EXCHANGE_FANOUT, "" ,null ,message.getBytes() );

            System.out.println("已经发送消息:"+message);

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(channel != null){
                try {
                    channel.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }


    }
}
7.3.2.消息接收者1
public class Rev {

    //队列的名字
    private static final String FANOUT_QUEUE_1 = "fanout_queue_1";

    //交换机的名字
    private static final String EXCHANGE_FANOUT = "exchange_fanout";

    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            channel.queueDeclare(FANOUT_QUEUE_1, false, false, false, null);

            //4.队列绑定交换机
            channel.queueBind(FANOUT_QUEUE_1, EXCHANGE_FANOUT, "");

            //设置同时处理一个消息
            channel.basicQos(1);

            Consumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {
                    //交换机
                    String exchange = envelope.getExchange();
                    //System.out.println("exchange:"+exchange);
                    //路由key
                    String routingKey = envelope.getRoutingKey();
                    //System.out.println("routingKey:"+routingKey);
                    //消息id
                    long deliveryTag = envelope.getDeliveryTag();
                    System.out.println("deliveryTag:"+deliveryTag);
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("收到消息:" + msg);
                    //System.out.println(1 / 0);

                    channel.basicAck(deliveryTag, false);
                }
            };

            //4.接受消息 :队列 ; 签收方式(true:自动签收)
            channel.basicConsume(FANOUT_QUEUE_1, false,consumer);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

7.3.3.消息接收者2
public class Rev2 {

    //队列的名字
    private static final String FANOUT_QUEUE_2 = "fanout_queue_2";

    //交换机的名字
    private static final String EXCHANGE_FANOUT = "exchange_fanout";

    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            channel.queueDeclare(FANOUT_QUEUE_2, false, false, false, null);

            //4.队列绑定交换机
            channel.queueBind(FANOUT_QUEUE_2, EXCHANGE_FANOUT, "");

            //设置同时处理一个消息
            channel.basicQos(1);

            Consumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {
                    //交换机
                    String exchange = envelope.getExchange();
                    //System.out.println("exchange:"+exchange);
                    //路由key
                    String routingKey = envelope.getRoutingKey();
                    //System.out.println("routingKey:"+routingKey);
                    //消息id
                    long deliveryTag = envelope.getDeliveryTag();
                    System.out.println("deliveryTag:"+deliveryTag);
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("收到消息:" + msg);
                    //System.out.println(1 / 0);

                    channel.basicAck(deliveryTag, false);
                }
            };

            //4.接受消息 :队列 ; 签收方式(true:自动签收)
            channel.basicConsume(FANOUT_QUEUE_2, false,consumer);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
8.direct定向模式

direct定向模式是交换机根据product指定的routingkey,收到消息后去匹配指定routingkey的队列,将消息发送给队列,消费者进行消费

8.1.工作模式

在这里插入图片描述

P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。

X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与routing key完全匹配的队列

C1:消费者,其所在队列指定了需要routing key 为 error 的消息

C2:消费者,其所在队列指定了需要routing key 为 info、error、warning 的消息
8.2.direct实现
8.2.1.发送者
public class Sen {

    //交换机的名字
    private static final String EXCHANGE_DIRECT = "exchange_direct";

    public static void main(String[] args) {
        Connection connection = null;
        Channel channel = null;
        try{
            //1.创建链接对象
            connection = ConnectionUtil.getConnection();

            //2.创建通道
            channel = connection.createChannel();

            //3.声明交换机指定类型为DIRECT
            channel.exchangeDeclare(EXCHANGE_DIRECT, BuiltinExchangeType.DIRECT);

            //4.发送消息:交换机 ; 队列名(routingkey) ;参数 ;消息了内容
            String message = "我是一个DIRECT消息";

            //使用 定向的交换机 ,往 rotingkey为 update的队列中发送消息
            channel.basicPublish(EXCHANGE_DIRECT, "delete" ,null ,message.getBytes() );

            System.out.println("已经发送消息:"+message);
...
8.2.2.接收者
public class Rev {

    //队列的名字
    private static final String DIRECT_QUEUE_1 = "direct_queue_1";

    //交换机的名字
    private static final String EXCHANGE_DIRECT = "exchange_direct";

    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            channel.queueDeclare(DIRECT_QUEUE_1, false, false, false, null);

            //4.队列绑定交换机
            channel.queueBind(DIRECT_QUEUE_1, EXCHANGE_DIRECT, "update");
            channel.queueBind(DIRECT_QUEUE_1, EXCHANGE_DIRECT, "delete");

            //设置同时处理一个消息
            channel.basicQos(1);

            Consumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {
                    //交换机
                    String exchange = envelope.getExchange();
                    //System.out.println("exchange:"+exchange);
                    //路由key
                    String routingKey = envelope.getRoutingKey();
                    //System.out.println("routingKey:"+routingKey);
                    //消息id
                    long deliveryTag = envelope.getDeliveryTag();
                    System.out.println("deliveryTag:"+deliveryTag);
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("收到消息:" + msg);
                    //System.out.println(1 / 0);

                    channel.basicAck(deliveryTag, false);
                }
            };

            //4.接受消息 :队列 ; 签收方式(true:自动签收)
            channel.basicConsume(DIRECT_QUEUE_1, false,consumer);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

注意:多个消息接收者,只需要声明不同的队列即可 , 交换机是相同的 ,并且绑定队列的时候要指定队列的routingkey

9.topic通配符

topic的工作模式跟 direct是一样的 , direct定向模式是交换机根据product指定的routingkey,收到消息后去匹配指定routingkey的队列,将消息发送给队列,消费者进行消费 , 只是不一样的是,消费者在绑定队列的时候队列的routingkey可以使用通配符

9.1.topic工作模式

在这里插入图片描述

# 匹配多个
* 匹配一个
9.1.topic代码实现
9.1.1.发送者
public class Sen {

    //交换机的名字
    private static final String EXCHANGE_TOPIC = "exchange_topic";

    public static void main(String[] args) {
        Connection connection = null;
        Channel channel = null;
        try{
            //1.创建链接对象
            connection = ConnectionUtil.getConnection();

            //2.创建通道
            channel = connection.createChannel();

            //3.声明交换机指定类型为TOPIC
            channel.exchangeDeclare(EXCHANGE_TOPIC, BuiltinExchangeType.TOPIC);

            //4.发送消息:交换机 ; 队列名(routingkey) ;参数 ;消息了内容
            String message = "我是一个TOPIC消息";

            //使用 定向的交换机 ,往 rotingkey为 update的队列中发送消息
            channel.basicPublish(EXCHANGE_TOPIC, "user.update" ,null ,message.getBytes() );

            System.out.println("已经发送消息:"+message);

...

9.1.2.接收者

public class Rev2 {

    //队列的名字
    private static final String TOPIC_QUEUE_2 = "topic_queue_2";

    //交换机的名字
    private static final String EXCHANGE_TOPIC = "exchange_topic";

    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            channel.queueDeclare(TOPIC_QUEUE_2, false, false, false, null);

            //4.队列绑定交换机 , routingkey使用通配符
            channel.queueBind(TOPIC_QUEUE_2, EXCHANGE_TOPIC, "user.*");

            //设置同时处理一个消息
            channel.basicQos(1);

            Consumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {
                    //交换机
                    String exchange = envelope.getExchange();
                    //System.out.println("exchange:"+exchange);
                    //路由key
                    String routingKey = envelope.getRoutingKey();
                    //System.out.println("routingKey:"+routingKey);
                    //消息id
                    long deliveryTag = envelope.getDeliveryTag();
                    System.out.println("deliveryTag:"+deliveryTag);
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("收到消息:" + msg);
                    //System.out.println(1 / 0);

                    channel.basicAck(deliveryTag, false);
                }
            };

            //4.接受消息 :队列 ; 签收方式(true:自动签收)
            channel.basicConsume(TOPIC_QUEUE_2, false,consumer);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

注意:不是说一样就非得使用通配符

10.header模式
10.1.工作模式

header模式与routing不同的地方在于,header模式取消routingkey,使用header中的 key/value(键值对)匹配 队列。

案例: 根据用户的通知设置去通知用户,设置接收Email的用户只接收Email,设置接收sms的用户只接收sms,设置两种 通知类型都接收的则两种通知都有效。

10.2.实现
10.2.1发送者
public class Sen {

    //交换机的名字
    public static final String EXCHANGE_HEADER = "exchange_header";

    public static void main(String[] args) {
        Connection connection = null;
        Channel channel = null;
        try{
            //1.创建链接对象
            connection = ConnectionUtil.getConnection();

            //2.创建通道
            channel = connection.createChannel();

            //3.声明交换机指定类型为TOPIC
            channel.exchangeDeclare(EXCHANGE_HEADER, BuiltinExchangeType.HEADERS);

            //4.发送消息:交换机 ; 队列名(routingkey) ;参数 ;消息了内容
            String message = "我是一个header消息";

            //使用 定向的交换机 ,往 rotingkey为 update的队列中发送消息

            Map<String,Object> headers = new Hashtable<String, Object>();
            headers.put("inform_type_email", "email");//匹配email通知消费者绑定的header
            headers.put("inform_type_sms", "sms");//匹配email通知消费者绑定的header

            AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder();
            properties.headers(headers);

            channel.basicPublish(EXCHANGE_HEADER, "" ,properties.build() ,message.getBytes() );

            System.out.println("已经发送消息:"+message);

10.2.2接收者
public class Rev {

    //队列的名字
    private static final String HEADER_QUEUE_1 = "header_queue_1";


    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            channel.queueDeclare(HEADER_QUEUE_1, false, false, false, null);

            //4.队列绑定交换机
            Map<String, Object> headersEmail = new Hashtable<String, Object>();
            headersEmail.put("inform_type_email", "email");
            channel.queueBind(HEADER_QUEUE_1, Sen.EXCHANGE_HEADER, "",headersEmail);

            //设置同时处理一个消息
            channel.basicQos(1);

            Consumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {
                    //交换机
                    String exchange = envelope.getExchange();
                    //System.out.println("exchange:"+exchange);
                    //路由key
                    String routingKey = envelope.getRoutingKey();
                    //System.out.println("routingKey:"+routingKey);
                    //消息id
                    long deliveryTag = envelope.getDeliveryTag();
                    System.out.println("deliveryTag:"+deliveryTag);
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("收到消息:" + msg);
                    //System.out.println(1 / 0);

                    channel.basicAck(deliveryTag, false);
                }
            };

            //4.接受消息 :队列 ; 签收方式(true:自动签收)
            channel.basicConsume(HEADER_QUEUE_1, false,consumer);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
11.持久化
11.1交换机持久化

在这里插入图片描述

11.2.队列持久化

在这里插入图片描述

11.3.消息持久化

在这里插入图片描述

12.如何避免消息丢失?
12.1 .手动签收

消费者的ACK机制。可以防止消费者丢失消息。

12.2 .持久化

持久化可以防止消费者丢失消息。

13.SpringBoot集成RabbitMQ
13.1.导入依赖
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!--spirngboot集成rabbitmq-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

    </dependencies>
13.2.创建主配置类
13.3.创建配置文件
...
rabbitmq:
  host: 127.0.0.1
  port: 5672
  username: guest
  password: guest
  virtualHost: /
13.4.创建Rabbitmq的配置类
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MQConfig {
    //针对发邮件的队列
    public static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
    //针对发短信的队列
    public static final String QUEUE_INFORM_SMS = "queue_inform_sms";
    //交换机,类型是topics
    public static final String EXCHANGE_TOPICS_INFORM = "exchange_topics_inform";

    /**
     * 交换机配置
     * ExchangeBuilder提供了fanout、direct、topic、header交换机类型的配置
     */
    @Bean(EXCHANGE_TOPICS_INFORM)
    public Exchange EXCHANGE_TOPICS_INFORM() {
        //durable(true)持久化,消息队列重启后交换机仍然存在
        return ExchangeBuilder.topicExchange(EXCHANGE_TOPICS_INFORM).durable(true).build();
    }

    //声明队列:针对sms的队列
    @Bean(QUEUE_INFORM_SMS)
    public Queue QUEUE_INFORM_SMS() {
        Queue queue = new Queue(QUEUE_INFORM_SMS);
        return queue;
    }

    //声明队列:针对于emial的队列
    @Bean(QUEUE_INFORM_EMAIL)
    public Queue QUEUE_INFORM_EMAIL() {
        Queue queue = new Queue(QUEUE_INFORM_EMAIL);
        return queue;
    }

    /**
     * channel.queueBind(INFORM_QUEUE_SMS,"inform_exchange_topic","inform.#.sms.#");
     * 绑定队列到交换机 .
     * 把:SMS的队列绑定到交换机,并且指定该队列的routingkey为   "inform.#.sms.#"
     */
    @Bean
    public Binding BINDING_QUEUE_INFORM_SMS(
            @Qualifier(QUEUE_INFORM_SMS) Queue queue,
            @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {

        return BindingBuilder.bind(queue).to(exchange).with("inform.sms.#").noargs();
    }

    /**
     * 把:EMAIL的队列绑定到交换机,并且指定该队列的routingkey为   "inform.#.email.#"
     */
    @Bean
    public Binding BINDING_QUEUE_INFORM_EMAIL(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
                                              @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("inform.email.#").noargs();
    }
}
13.5.创建发送者
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MQConfig {
    //针对发邮件的队列
    public static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
    //针对发短信的队列
    public static final String QUEUE_INFORM_SMS = "queue_inform_sms";
    //交换机,类型是topics
    public static final String EXCHANGE_TOPICS_INFORM = "exchange_topics_inform";

    /**
     * 交换机配置
     * ExchangeBuilder提供了fanout、direct、topic、header交换机类型的配置
     */
    @Bean(EXCHANGE_TOPICS_INFORM)
    public Exchange EXCHANGE_TOPICS_INFORM() {
        //durable(true)持久化,消息队列重启后交换机仍然存在
        return ExchangeBuilder.topicExchange(EXCHANGE_TOPICS_INFORM).durable(true).build();
    }

    //声明队列:针对sms的队列
    @Bean(QUEUE_INFORM_SMS)
    public Queue QUEUE_INFORM_SMS() {
        Queue queue = new Queue(QUEUE_INFORM_SMS);
        return queue;
    }

    //声明队列:针对于emial的队列
    @Bean(QUEUE_INFORM_EMAIL)
    public Queue QUEUE_INFORM_EMAIL() {
        Queue queue = new Queue(QUEUE_INFORM_EMAIL);
        return queue;
    }

    /**
     * channel.queueBind(INFORM_QUEUE_SMS,"inform_exchange_topic","inform.#.sms.#");
     * 绑定队列到交换机 .
     * 把:SMS的队列绑定到交换机,并且指定该队列的routingkey为   "inform.#.sms.#"
     */
    @Bean
    public Binding BINDING_QUEUE_INFORM_SMS(
            @Qualifier(QUEUE_INFORM_SMS) Queue queue,
            @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {

        return BindingBuilder.bind(queue).to(exchange).with("inform.sms.#").noargs();
    }

    /**
     * 把:EMAIL的队列绑定到交换机,并且指定该队列的routingkey为   "inform.#.email.#"
     */
    @Bean
    public Binding BINDING_QUEUE_INFORM_EMAIL(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
                                              @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("inform.email.#").noargs();
    }
}
13.6.创建消费者
@Component
public class RevHandler {

    //消费sms
    @RabbitListener(queues = MQConfig.QUEUE_INFORM_SMS)
    public void smsHandler(String msg , Message message , Channel channel){
        System.out.println("sms收到消息:"+msg);
    }


    //消费email
    @RabbitListener(queues = MQConfig.QUEUE_INFORM_EMAIL)
    public void emailHandler(String msg , Message message , Channel channel){
        System.out.println("email收到消息:"+msg);
    }
}
RabbitMQ 集群 RabbitMQ 作为消息中间件,可以与多个生产者和消费者进行绑定,但是如何只有一台 RabbitMQ 服务的话,那么这个 RabbitMQ 就需要处理很多的请求,如果该 RabbitMQ 节点挂掉了之后,那么所有与之相关的操作都无法进行了。我们可以升级 RabbitMQ 的硬件设施,提升 RabbitMQ 的处理能力,但是硬件的升级成本是很高的,比较好的解决方法就是搭建 RabbitMQ 集群。 阅读详情

相关推荐

基于LTspice的共模电感差模/共模插入损耗仿真指南

在电源与EMC设计领域,插入损耗是衡量滤波器件抑制噪声能力的核心指标。共模电感作为EMI滤波器中最常见的元器件之一,其差模与共模插入损耗特性直接影响整体滤波方案的合规性。然而,仅依赖规格书曲线往往难以覆盖真实应用中的阻抗条件,借助SPICE仿真工具进行电路级验证已成为工程师常用的手段。LTspice凭借其轻量、高效的交流分析能力,能够帮助设计者快速搭建共模电感等效模型,并通过调整耦合系数、寄生电容等参数,还原漏感与谐振行为。本文以Wurth Elektronik的WE 744821201型号为例,从基本测试

weixin_27252001的博客 290

RabbitMQ

RabbitMQ依赖于Erlang、socat,因此要首先安装Erlang与socat 1.RabbitMQ简介: RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。 2.RabbitMQ安装依赖: 2.1 由于RabbitMQ是基于Erlang语言开发, 所以在安装RabbitMQ之前, 需要先安装Erlang ,r

qq_45518589的博客 567

别再为多相机标定头疼了!用VisionMaster统一坐标系的保姆级教程

本文详细介绍了使用VisionMaster平台解决多相机视觉系统中坐标系统一问题的完整流程。从标定板选择到N点标定,再到实战演练,提供了从原理到落地的全方位指导,帮助工程师高效解决多相机定位引导中的坐标偏差问题。

weixin_38168322的博客 631

rabbitMQ的详细介绍

rabbitMQ的详细介绍

wang20010104的博客 7万+

Allegro File菜单实战指南:从导入网表到导出BOM的完整流程

PCB设计离不开对EDA软件菜单体系的深入理解。在Cadence Allegro中,File菜单是数据流转的中枢,它不仅是新建、打开、保存的基础入口,更是连接原理图与版图、设计与制造的关键桥梁。工程师常遇到的“导入网表报错”“导出BOM为空”“板框不闭合”等高频问题,大多源于对File菜单中Import与Export功能的理解不到位。从基础概念出发,先厘清Import(网表、DXF、IPC)与Export(BOM、ODB++、DXF)的工作原理,再结合版本兼容、封装库路径、单位设置等工程细节,即可构建完整的

weixin_32950759的博客 294

AutoCAD二次开发(.Net)之XData

对于CAD中的实体进行筛选等操作,常常会用到实体的XData属性,下面介绍一下实体的XData的增删改。 //XData的新增,修改跟新增一样,new一个ResultBuffer,赋值即可 Document doc=Application.DocumentManager.MdiActiveDocument; using (DocumentLock dl = doc.LockDocument()) { using (Transaction trans = doc.TransactionManager.S.

qq_21489689的博客 2591

【RabbitMQ】MQ的基本概念、RabbitMQ简介及安装

本文涉及MQ的基本概念、RabbitMQ简介、RabbitMQ的安装等内容

十八岁讨厌编程的博客 2万+

红外热成像仪原理及应用

目录什么是红外热成像背景介绍热成像技术原理热成像分类红外热成像和夜视仪之间的区别红外热像仪夜视仪红外照明相机对比红外热像仪都能看透什么如何选择制冷型和非制冷型红外热像仪制冷型红外热像仪非制冷型红外热像仪实例对比成像速度空间分辨率灵敏度光谱滤波同步何如选择合适的红外热像仪像素测温范围和被测物温度分辨率空间分辨率温度稳定性热像仪的距离系数比常见热成像仪关键参数量程视场角 (FOV)红外分辨率热灵敏度(NETD)焦距光谱范围精度内置优化分析NTED(热灵敏度)什么是NETD如何测量NETD?NETD如何影响测量?

zhy295006359的博客 2万+

RabbitMQ介绍以及基本使用

消息队列是一种用于在分布式系统中进行通信的技术。它是一种存储和转发消息的中间件,可以用于将应用程序之间的通信解耦,从而实现高效的异步通信。消息队列允许发送者将消息发送到队列中,而接收者则可以从队列中获取消息并进行处理。这种方式可以帮助系统实现高可用性、高性能、松耦合和可伸缩性。消息队列通常包括生产者(发送消息的应用程序)、消费者(接收消息的应用程序)和队列(存储消息的缓冲区)。RabbitMQ:是由erlang语言开发,基于AMQP(高级消息队列协议)协议实现的一种消息队列。市面上还有很多消息队列,比如Ka

qq_40950398的博客 2万+

WRF实战:自定义Vtable解析ECMWF海温数据的关键步骤与技巧

本文详细介绍了在WRF模型中自定义Vtable以解析ECMWF海温数据的关键步骤与技巧。通过解剖GRIB文件、编写自定义Vtable条目以及配置METGRID.TBL,解决了ECMWF数据与WRF模型对接的难题,为海洋气象和台风模拟研究提供了高精度数据输入方案。

weixin_29279101的博客 335

SAP S/4HANA Cloud 管理员业务角色创建实战:基于 SAP_BR_ADMINISTRATOR 模板的一站式指南

摘要:SAP S/4HANA Cloud新系统初始登录时常见Fiori Launchpad无磁贴的问题,这是由于缺乏合适的业务角色分配。本文介绍了通过预交付的SAP_BR_ADMINISTRATOR模板创建管理员角色的完整流程,包括业务用户、业务角色和业务目录的核心概念解析。重点说明了直接使用模板的风险,并提供了从模板创建自定义管理员角色的详细步骤(4.1-4.3),以及权限限制设置的注意事项。文中还分享了一个实际项目案例,强调正确配置管理员角色对后续权限体系建设的关键作用。(149字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 200

RabbitMQ详解

1.1 什么是MQ MQ(Message Quene) : 翻译为 消息队列,通过典型的 生产者和消费者模型,生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,轻松的实现系统间解耦。别名为 消息中间件 通过利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。 1.2 MQ有哪些 当今市面上有很多主流的消息中间件,如老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka

1万+

大数据平台符合信创(CDH国产化代替)详细方案(企业内部不外传方案)

信创旨在实现信息技术产业的自主可控,减少对外部技术的依赖,从而提升国家信息安全和经济发展的自主性。在此背景下,中国对信创提出了更高的要求,以期在激烈的市场竞争中占据有利地位。信创不仅关乎技术层面的创新,更涉及到产业链条的整合与优化。它要求从基础硬件、操作系统、数据库、中间件等各个层面实现国产替代,构建完整的信息技术生态体系。尤其是在做国企项目时,就有硬性要求使用符合信创(国产代替)。在信创背景下,符合要求的产品必须具备自主可控、安全可靠以及性能卓越等核心特点。

大模型大数据攻城狮的专栏 3508

win10 安装RabbitMQ时 执行:rabbitmq-plugins enable rabbitmq_management命令报 Plugin configuration unchanged

安装RabbitMQ时 执行:rabbitmq-plugins enable rabbitmq_management命令报 Plugin configuration unchanged

xin292930540的专栏 6571

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

【RabbitMQ】Windows下RabbitMQ的安装和部署

RabbitMQ在windows下安装部署

Hanson的博客 4064

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

RabbitMQ学习笔记:节点名称详解、rabbitmq-server、及rabbitmq-env.conf

rabbitmq-server rabbitmq-server 启动一个RabbitMQ节点 1.rabbitmq-server在前端启动一个RabbitMQ节点,示例如下: [root@rabbit3 rabbitmq]# rabbitmq-server ## ## RabbitMQ 3.8.1 ## ## ########## Copyright (c) 20...

OceanSky的专栏 1万+

【RabbitMQ实战】06 RabbitMQ配置

一般情况下,可以使用默认的内建配置来有效地运行RabbitMQ,并且大多数情况下也并不需要修改任何 RabbitMQ的配置。当然,为了更加有效地操控 RabbitMQ,也可以利用调节系统范围内的参数来达到定制化的需求。RabbitMQ提供了三种方式来定制化服务:(1)环境变量(Enviroment Variables )。RabbitMQ服务端参数可以通过环境变量进行配置,例如,节点名称、RabbitMQ配置文件的地址、节点内部通信端口等。(2)配置文件(Configuration File )

程序员笔记 2853

rabbitmq系列1——安装并使用rabbitmq

🔥本篇概览:详细讲解了安装并使用rabbitmq,并讲解了数据隔离而生的的virtualhost。🌈⭕🔥

做一个善良的人,做好自己的事,如果愿意,再发一份光。 2069

什么是RabbitMQ

同步通讯:就像打电话,需要实时响应。异步通信:就像发微信,不需要马上回复。两种方式各有优劣,打电话可以立即得到响应,但是你却不能跟多个人同时通话。发微信可以同时与多个人收发信息,但是往往响应会有延迟。学SpringCloud的时候,我们的Feign 其实就是同步通讯的,他其实有以下这几个缺点耦合度高:(每次有新的需求,都需要更改代码)性能下降:(消费者需要等待提供者响应,如果调用链过长,那么响应的时间等于每次调用的时间之和)资源浪费。

越努力越幸运的博客 2903

RabbitMQ——Docker搭建RabbitMQ集群

文章目录RabbitMQ——Docker搭建RabbitMQ集群1、普通集群的搭建1.1、普通集群架构介绍1.2、环境准备1.3、集群搭建2、镜像集群的搭建2.1、配置镜像集群的策略 RabbitMQ——Docker搭建RabbitMQ集群 集群模式介绍 RabbitMQ集群模式有两种:普通模式和镜像模式 普通模式:默认模式,多个节点组成的普通集群,消息随机发送到其中一个节点的队列上,其他节点仅保留元数据,各个节点仅有相同的元数据,即队列结构、交换器结构、交换器与队列绑定关系、vhost。消费者消费消

万里顾一程的博客 5803

laravel + rabbitmq

一、安装laravel 两种方式 1. composer global require laravel/installer laravel new wendao 2. composer create-project --prefer-dist laravel/laravel wendao 二、安装rabbitmq 1. docker pull rabbitmq:management //拉取rabbitmq 镜像 //启动容器 2.docker run -d --nam

rockywish的博客 6806

RabbitMQ 菜鸟安装、RabbitMQ初接触 AMQP 安装、配置指南

RabbitMQ安装: RabbitMQ是基于Erlang的,所以首先必须配置Erlang环境. 安装Erlang 进入到Erlang官网:http://www.erlang.org 进行下载 安装有两种方式: 1.1.源码安装方式: mkdir erlang cd erlang wget http://www.erlang.org/download/otp_src_R15B.t

hepeng_8的专栏 2878

RabbitMQ的基本使用

RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的。 一、消息队列 1、MQ:Message Queue释义 服务之间最常见的通信方式是直接调用彼此来通信,消息从一端发出后立即就可以达到另一端,称为即时消息通讯(同步通信) 消息从某一端发出后,首先进入一个容器进行临时存储,当达到某种条件后,再由这个容器发送给另一端,称为延迟消息通讯(异步通信) 2、消息队列特点.

qq_54936371的博客 3080

RabbitMQ 入门

MQ,中文是消息队列(MessageQueue),字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。比较常见的MQ实现:ActiveMQRabbitMQRocketMQKafka追求可用性(当需要处理数据时,资源处于可用状态的程度):Kafka、 RocketMQ 、RabbitMQ追求可靠性:RabbitMQ、RocketMQ追求吞吐能力(十万级别的):RocketMQ、Kafka追求消息低延迟:RabbitMQ、Kafka。

Java小白的博客 致力分享每一天学到的知识 1954

RabbitMQ 教程 | 第6章 RabbitMQ 配置

这篇 RabbitMQ 教程为学习者提供了全面的内容,帮助学习者充分掌握 RabbitMQ 的应用。整篇教程丰富内容详实,适合初学者和有经验的开发者参考学习。

编程洪同学 4048
上一篇: Nginx
虞铭轩、
博客等级 码龄7年 3粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值