RabbitMq订阅模式

RabbitMQ 工作原理

对于 RabbitMQ 来说, 除了这三个基本模块以外, 还添加了一个模块, 即交换机(Exchange). 它使得生产者和消息队列之间产生了隔离, 生产者将消息发送给交换机,而交换机则根据调度策略把相应的消息转发给对应的消息队列. 那么 RabitMQ 的工作流程如下所示:

说一下交换机: 交换机的主要作用是接收相应的消息并且绑定到指定的队列. 交换机有四种类型, 分别为Direct, topic, headers, Fanout.

Direct 是 RabbitMQ 默认的交换机模式,也是最简单的模式.即创建消息队列的时候,指定一个 BindingKey. 当发送者发送消息的时候, 指定对应的 Key. 当 Key 和消息队列的 BindingKey 一致的时候,消息将会被发送到该消息队列中.

topic 转发信息主要是依据通配符, 队列和交换机的绑定主要是依据一种模式(通配符+字符串), 而当发送消息的时候, 只有指定的 Key 和该模式相匹配的时候, 消息才会被发送到该消息队列中.

headers 也是根据一个规则进行匹配, 在消息队列和交换机绑定的时候会指定一组键值对规则, 而发送消息的时候也会指定一组键值对规则, 当两组键值对规则相匹配的时候, 消息会被发送到匹配的消息队列中.

Fanout 是路由广播的形式, 将会把消息发给绑定它的全部队列, 即便设置了 key, 也会被

 

 

1.生产者

package cn.zhm.util.simple;

import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

public class SendWork {
    /**
     * @Description:    java类作用描述

     * @Author:         zhaohaiming

     * @CreateDate:     2019/8/14 0:18

     * @Version:        1.0

     */
    private static final String QUEUE_NAME = "test_work_name";
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Connection connection = null;
        Channel channel = null;
    try {
        //获取连接
        connection = GetRabbitConnectUtil.getMQConnection();
        //从连接中获取一个通道
        channel =  connection.createChannel();

        //创建队列声明
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        for (int  i = 0 ;i <50;i++){
            //发送信息内容
            String msg = "hello work!!"+i;
            System.out.println("SendWork send msg信息:"+msg);
            channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());

            Thread.sleep(300);

        }

    }catch (Exception e){
        e.printStackTrace();
    }finally {
        channel.close();
        connection.close();
    }
    }
}

消费者

package cn.zhm.util.simple;

import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

public class ReceptionWork {
    /**
     * @Description:    消费者接收信息

     * @Author:         zhaohaiming

     * @CreateDate:     2019/8/11 21:58

     * @Version:        1.0

     */
    private static final String QUEUE_NAME = "test_work_name";
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Connection connection = null;
        Channel channel = null;
        try {
            //获取一个连接
            connection =  GetRabbitConnectUtil.getMQConnection();
            //从连接中获取一个通道
            channel =  connection.createChannel();

           //创建队列声明
            channel.queueDeclare(QUEUE_NAME,false,false,false,null);

            //获取消息

            DefaultConsumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                  //  super.handleDelivery(consumerTag, envelope, properties, body);
                    String smg = new String(body,"utf-8");
                    System.out.println("消费者接收消息:"+smg);

                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println("is down");
                    }
                }
            };

            //监听队列
            channel.basicConsume(QUEUE_NAME,true,consumer);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
           // channel.close();
           // connection.close();
        }

    }
}
//监听队列
channel.basicConsume(QUEUE_NAME,true,consumer);

ture :(自动确认模式) 一旦rabbitmq将消息分发给消费者,就会从内容中删除,

这种情况下,如果杀死正在执行的消费者,就会丢失正在处理的消息

 

flase :(手动模式),如果 有一个消费者挂掉,就会交付给其他消费者。rabbitMq支持消应答,消费者发送一个消息应答,告诉rabitMq这个消息我已经处理完,你可以删除,,然后rabbitmq就删除内存中的消息

默认是flase

消息的持久

//创建队列声明
  boolean durable = false;
  channel.queueDeclare(QUEUE_NAME,durable,false,false,null);
已经设置durable=false 不能再修改成为ture,尽管代码是正确的,他也不会运行成功,因为我们已经定义了一个 test_work_name这个queue是未持久化rabbitmq不准许重新定义(不同参数)一个已经存在的队列。

订阅模型

解读

1.一个生产者,多个消费者

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

3.生产者没有直接把消息发送到队列,而是发到了交换机转发器到exchanger

4.每个队列都是要在绑定到交换器上

5.生产者发送的消息经过交换机,到达队列  一个消息对应多个消费者消费

注册  -》 邮件 ——》短信

生产者

package cn.zhm.util.su;

import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class Send {
    /**
     * @Description:    订阅 生产者

     * @Author:         zhaohaiming

     * @CreateDate:     2019/8/15 0:42

     * @Version:        1.0

     */
    private static final String EXCHANGE_NAME = "exchange_test";
    public static void main(String[] args) throws IOException, TimeoutException {
        // TODO Auto-generated method stub
        Connection connection = null;
        Channel channel = null;
        try {
            //获取一个连接
            connection =  GetRabbitConnectUtil.getMQConnection();
            //从连接中获取一个通道
            channel =  connection.createChannel();
            channel.exchangeDeclare(EXCHANGE_NAME, "fanout");//fanout 分发 广播形式
            String message = "Hello wordle exchang....";
            channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("UTF-8"));
            System.out.println(" [x] Sent '" + message + "'");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            channel.close();
            connection.close();
        }

    }
}

消息到那去了 ?? 丢失了 因为交换机没有存储的能力,在rabbitmq里面只有队列有存储能力。

因为这个时候还没有队列绑定到这个交换机所以数据丢失了

 

消费者1

package cn.zhm.util.su;

import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

public class Reception {
    /**
     * @Description:    订阅 消费者

     * @Author:         zhaohaiming

     * @CreateDate:     2019/8/15 0:59

     * @Version:        1.0

     */
    private static final String QUEUE_NAME = "test_sub_name_info";
    private static final String EXCHANGE_NAME = "exchange_test";
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Connection connection = null;
        Channel channel = null;
        try {
            //获取一个连接
            connection =  GetRabbitConnectUtil.getMQConnection();
            //从连接中获取一个通道
            channel =  connection.createChannel();

            //创建队列声明
            boolean durable = false;
            channel.queueDeclare(QUEUE_NAME,durable,false,false,null);

            //绑定交换机
            String queueName = channel.queueDeclare().getQueue();
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

            //获取消息

            DefaultConsumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    //  super.handleDelivery(consumerTag, envelope, properties, body);
                    String smg = new String(body,"utf-8");
                    System.out.println("test_sub_name_info_消费者接收消息:"+smg);

                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println("test_sub_name_info is down");
                    }
                }
            };

            //监听队列
            channel.basicConsume(QUEUE_NAME,true,consumer);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // channel.close();
            // connection.close();
        }
    }
}

运行结果:

test_sub_name_info_消费者接收消息:Hello wordle exchang....
test_sub_name_info is down

消费者2

package cn.zhm.util.su;

import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

public class ReceptionEmail {
    /**
     * @Description:    订阅 消费者

     * @Author:         zhaohaiming

     * @CreateDate:     2019/8/15 0:59

     * @Version:        1.0

     */
    private static final String QUEUE_NAME = "test_sub_name_email";
    private static final String EXCHANGE_NAME = "exchange_test";
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Connection connection = null;
        Channel channel = null;
        try {
            //获取一个连接
            connection =  GetRabbitConnectUtil.getMQConnection();
            //从连接中获取一个通道
            channel =  connection.createChannel();

            //创建队列声明
            boolean durable = false;
            channel.queueDeclare(QUEUE_NAME,durable,false,false,null);

            //绑定交换机
            String queueName = channel.queueDeclare().getQueue();
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

            //获取消息

            DefaultConsumer consumer = new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    //  super.handleDelivery(consumerTag, envelope, properties, body);
                    String smg = new String(body,"utf-8");
                    System.out.println("test_sub_name_email_消费者接收消息:"+smg);

                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println("test_sub_name_email is down");
                    }
                }
            };

            //监听队列
            channel.basicConsume(QUEUE_NAME,true,consumer);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // channel.close();
            // connection.close();
        }
    }
}

运行结果:

test_sub_name_email_消费者接收消息:Hello wordle exchang....
test_sub_name_email is down

6.Exchange(交换机,转发器)

一方面是接收生产的消息,另一方面是向队列推送消息

匿名转发: “”

Fanout(不处理路由键)

Direct (处理路由键)

路由模式

模型

生产者:

package routing;

import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * @description: 路由模式发送者
 * @author: zhaohaiming
 * @Version V1.0.0
 * @create: 2019-08-17 00:11
 **/
public class Send {
    /**
     * @Description: java类作用描述
     * @Author: zhaohaiming
     * @CreateDate: 2019/8/17 0:13
     * @Version: 1.0
     */
    private static final String QUEUE_NAME = "test_rout_name";
    private static final String EXCHANF_NAME = "exchan_name";

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Connection connection = null;
        Channel channel = null;
        try {
            //获取一个连接
            connection = GetRabbitConnectUtil.getMQConnection();
            //从连接中获取一个通道
            channel = connection.createChannel();

            //Exchang
            channel.exchangeDeclare(EXCHANF_NAME, "direct");//处理路由键
            String smg = "send diret megges!";
            String rountKey = "error";//路由key

            //发送信息
            channel.basicPublish(EXCHANF_NAME,rountKey,null,smg.getBytes());

            System.out.println("send===>"+smg);

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            channel.close();
            connection.close();
        }

    }
}

消费者1

package routing;

import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @description: 路由模式消费者
 * @author: zhaohaiming
 * @Version V1.0.0
 * @create: 2019-08-17 00:48
 **/
public class Reception {
    /**
     * @Description:    java类作用描述
     * @Author:         zhaohaiming
     * @CreateDate:     2019/8/17 0:49
     * @Version:        1.0

     */
    private static final String QUEUE_NAME = "queue_rout_name";
    private static final String EXCHANF_NAME = "exchan_name";
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Connection connection = null;
        Channel channel = null;
        try {
            //获取一个连接
            connection =  GetRabbitConnectUtil.getMQConnection();
            //从连接中获取一个通道
            channel =  connection.createChannel();

            //创建队列声明
            channel.queueDeclare(QUEUE_NAME,false,false,false,null);

            //交换机与路由绑定
            channel.queueBind(QUEUE_NAME,EXCHANF_NAME,"error");

            channel.basicQos(1);

            //获取消息
            final Channel finalChannel = channel;
            DefaultConsumer consumer = new DefaultConsumer(finalChannel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    //  super.handleDelivery(consumerTag, envelope, properties, body);
                    String smg = new String(body,"utf-8");
                    System.out.println("消费者接收消息:"+smg);

                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println("1111is down");
                        finalChannel.basicAck(envelope.getDeliveryTag(),false);
                    }
                }
            };

            //监听队列
            boolean auteAck = false ; //自动回答消息
            channel.basicConsume(QUEUE_NAME,auteAck,consumer);

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

消费者2

package routing;

import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.*;

import java.io.IOException;

/**
 * @description: 路由模式消费者
 * @author: zhaohaiming
 * @Version V1.0.0
 * @create: 2019-08-17 00:48
 **/
public class Reception2 {
    /**
     * @Description:    java类作用描述
     * @Author:         zhaohaiming
     * @CreateDate:     2019/8/17 0:49
     * @Version:        1.0

     */
    private static final String QUEUE_NAME = "queue_rout_name2";
    private static final String EXCHANF_NAME = "exchan_name";
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Connection connection = null;
        Channel channel = null;
        try {
            //获取一个连接
            connection =  GetRabbitConnectUtil.getMQConnection();
            //从连接中获取一个通道
            channel =  connection.createChannel();

            //创建队列声明
            channel.queueDeclare(QUEUE_NAME,false,false,false,null);

            //交换机与路由绑定
            channel.queueBind(QUEUE_NAME,EXCHANF_NAME,"error");
            channel.queueBind(QUEUE_NAME,EXCHANF_NAME,"info");
            channel.queueBind(QUEUE_NAME,EXCHANF_NAME,"warning");

            channel.basicQos(1);

            //获取消息
            final Channel finalChannel = channel;
            DefaultConsumer consumer = new DefaultConsumer(finalChannel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    //  super.handleDelivery(consumerTag, envelope, properties, body);
                    String smg = new String(body,"utf-8");
                    System.out.println("消费者接收消息:"+smg);

                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println("22222is down");
                        finalChannel.basicAck(envelope.getDeliveryTag(),false);
                    }
                }
            };

            //监听队列
            boolean auteAck = false ; //自动回答消息
            channel.basicConsume(QUEUE_NAME,auteAck,consumer);

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

运行结果

当发送是 error 时 消费1 和消费2都能接收信息

发送者发送信息:

send===>send diret megges!

消费1 收到消息:
消费者接收消息:send diret megges!
1111is down

消费2 收到消息:

消费者接收消息:send diret megges!
22222is down

 

当发送是 info 时 只有消费2能接收信息,消费1收不消息

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值