订阅模式

公众号-->订阅之后才会收到相应的文章。

解读:
1.一个生产者,多个消费者
2.每个消费者都有自己的队列
3.生产者没有将消息直接发送到队列里,而是发送给了交换机(转发器)exchange
4.每个队列都要绑定到交换机(转发器)上
5.生产者发送的消息记过交换机然后到达队列,然后就能实现被多个消费者消费

图例:

     |-------------|-----Q-----C3

P------------X-------------|-----Q-----C3

     |-------------|-----Q-----C3

注册--->发邮件--->发短信

MQ工厂类Connection

  1. package com.mmr.rabbitmq.util;
  2.  
  3. import java.io.IOException;
  4.  
  5. import com.rabbitmq.client.Connection;
  6. import com.rabbitmq.client.ConnectionFactory;
  7.  
  8. public class ConnectionUtils {
  9. /**
  10. * @desc 获取Mq 的链接
  11. * @author zp
  12. * @throws IOException
  13. * @date 2018-7-19
  14. */
  15. public static Connection getConnection() throws IOException {
  16. // 1.定义一个链接工厂
  17. ConnectionFactory factroy = new ConnectionFactory();
  18.  
  19. // 2.设置服务地址
  20. factroy.setHost("127.0.0.1");
  21.  
  22. // 3.设置端口号
  23. factroy.setPort(5672);
  24.  
  25. // 4.vhost 设置数据库
  26. factroy.setVirtualHost("vhtest");
  27.  
  28. // 5.设置用户名
  29. factroy.setUsername("jerry");
  30.  
  31. // 6. 设置密码
  32. factroy.setPassword("123456");
  33.  
  34. // 7.返回链接
  35. return factroy.newConnection();
  36. }
  37. }

消息生产者类Send,这个时候,运行代码再到控制台去查看,并没有发现我们的消息,因为在MQ中只有队列可以存储消息,而交换机不可以存储消息,下面这段代码并没有将交换机和队列进行绑定,所以数据就丢失了。

  1. package com.mmr.rabbitmq.ps;
  2.  
  3. import java.io.IOException;
  4.  
  5. import com.mmr.rabbitmq.util.ConnectionUtils;
  6. import com.rabbitmq.client.Channel;
  7. import com.rabbitmq.client.Connection;
  8.  
  9. public class Send {
  10. private static final String EXCHANGE_NAME="test_exchange_fanout";
  11. public static void main(String[] args) throws IOException {
  12. // 创建连接
  13. Connection connection = ConnectionUtils.getConnection();
  14.  
  15. // 获取通道
  16. Channel channel = connection.createChannel();
  17.  
  18. // 声明交换机
  19. channel.exchangeDeclare(EXCHANGE_NAME, "fanout");// fanout 分发
  20.  
  21. // 发送消息
  22. String msg = "hello ps";
  23.  
  24. channel.basicPublish(EXCHANGE_NAME, "", null, msg.getBytes());
  25. System.out.println("send:"+msg);
  26. channel.close();
  27. connection.close();
  28.  
  29. }
  30. }

代码运行后的控制台:

由于交换机不能存储数据,那么我们就需要考虑如何将交换机和队列进行绑定。因为只要将两者进行绑定之后,那么数据存储问题就迎刃而解。

消费者Recv1 Recv2

  1. package com.mmr.rabbitmq.ps;
  2.  
  3. import java.io.IOException;
  4.  
  5. import com.mmr.rabbitmq.util.ConnectionUtils;
  6. import com.rabbitmq.client.Channel;
  7. import com.rabbitmq.client.Connection;
  8. import com.rabbitmq.client.Consumer;
  9. import com.rabbitmq.client.DefaultConsumer;
  10. import com.rabbitmq.client.Envelope;
  11. import com.rabbitmq.client.AMQP.BasicProperties;
  12.  
  13. public class Recv1 {
  14. private static final String QUEUE_NAME_STRING="test_queue_fanout_email";
  15. private static final String EXCHANGE_NAME="test_exchange_fanout";
  16. public static void main(String[] args) throws IOException {
  17. // 创建连接
  18. Connection connection = ConnectionUtils.getConnection();
  19.  
  20. // 创建通道
  21. final Channel channel = connection.createChannel();
  22.  
  23. // 声明队列
  24. channel.queueDeclare(QUEUE_NAME_STRING, false, false, false, null);
  25.  
  26. // 绑定队列,绑定到交换机/转发器
  27. channel.queueBind(QUEUE_NAME_STRING, EXCHANGE_NAME, "");
  28.  
  29. // 保证每次只分发一个
  30. channel.basicQos(1);
  31.  
  32. // 定义一个消费者
  33. Consumer consumer = new DefaultConsumer(channel){
  34. @Override
  35. public void handleDelivery(String consumerTag, Envelope envelope,
  36. BasicProperties properties, byte[] body) throws IOException {
  37. // TODO Auto-generated method stub
  38. String msg = new String(body,"utf-8");
  39. System.out.println("[1]Recv msg:"+msg);
  40. try {
  41. // 每次休息一会儿
  42. Thread.sleep(2000);
  43. } catch (Exception e) {
  44. // TODO: handle exception
  45. e.printStackTrace();
  46. }finally{
  47. System.out.println("recv1 done");
  48. //回执
  49. channel.basicAck(envelope.getDeliveryTag(), false);
  50. }
  51. }
  52. };
  53. boolean autoAck = false;// 不自动应答
  54. channel.basicConsume(QUEUE_NAME_STRING, autoAck,consumer);
  55.  
  56. }
  57. }
  1. package com.mmr.rabbitmq.ps;
  2.  
  3. import java.io.IOException;
  4.  
  5. import com.mmr.rabbitmq.util.ConnectionUtils;
  6. import com.rabbitmq.client.Channel;
  7. import com.rabbitmq.client.Connection;
  8. import com.rabbitmq.client.Consumer;
  9. import com.rabbitmq.client.DefaultConsumer;
  10. import com.rabbitmq.client.Envelope;
  11. import com.rabbitmq.client.AMQP.BasicProperties;
  12.  
  13. public class Recv2 {
  14. private static final String QUEUE_NAME_STRING="test_queue_fanout_sms";
  15. private static final String EXCHANGE_NAME="test_exchange_fanout";
  16. public static void main(String[] args) throws IOException {
  17. // 创建连接
  18. Connection connection = ConnectionUtils.getConnection();
  19.  
  20. // 创建通道
  21. final Channel channel = connection.createChannel();
  22.  
  23. // 声明队列
  24. channel.queueDeclare(QUEUE_NAME_STRING, false, false, false, null);
  25.  
  26. // 绑定队列,绑定到交换机/转发器
  27. channel.queueBind(QUEUE_NAME_STRING, EXCHANGE_NAME, "");
  28.  
  29. // 保证每次只分发一个
  30. channel.basicQos(1);
  31.  
  32. // 定义一个消费者
  33. Consumer consumer = new DefaultConsumer(channel){
  34. @Override
  35. public void handleDelivery(String consumerTag, Envelope envelope,
  36. BasicProperties properties, byte[] body) throws IOException {
  37. // TODO Auto-generated method stub
  38. String msg = new String(body,"utf-8");
  39. System.out.println("[2]Recv msg:"+msg);
  40. try {
  41. // 每次休息一会儿
  42. Thread.sleep(2000);
  43. } catch (Exception e) {
  44. // TODO: handle exception
  45. e.printStackTrace();
  46. }finally{
  47. System.out.println("recv2 done");
  48. //回执
  49. channel.basicAck(envelope.getDeliveryTag(), false);
  50. }
  51. }
  52. };
  53. boolean autoAck = false;// 不自动应答
  54. channel.basicConsume(QUEUE_NAME_STRING, autoAck,consumer);
  55.  
  56. }
  57. }

运行上述代码进行监听,再通过运行Send发送消息,我们可以在MQ-管理平台上看到:

进过这样的使用,我们的消息订阅就完成了。

RabbitMQ简单应用の订阅模式的更多相关文章

  1. RabbitMQ的发布订阅模式(Publish/Subscribe)

    一.发布/订阅(Publish/Subscribe)模式 发布订阅是我们经常会用到的一种模式,生产者生产消息后,所有订阅者都可以收到.RabbitMQ的发布/订阅模型图如下: 1.该模式下生产者并不是 ...

  2. RabbitMQ入门-消息订阅模式

    消息派发 上篇<RabbitMQ入门-消息派发那些事儿>发布之后,收了不少反馈,其中问的最多的还是有关消息确认以及超时等场景的处理. 楼主,有遇到消费者后台进程不在,但consumer连接 ...

  3. RabbitMQ入门-发布订阅模式

    兔子的Publish/Subscribe是这样的: 有个生产者P,X代表交换机,交换机绑定队列,消费者从队列中取得消息.每次有消息,先发到交换机中,然后由交换机负责发送到它已知的队列中. 生产者代码: ...

  4. RabbitMQ简单应用の主题模式(topic)

    Topic exchange(主题转发器) 发送给主题转发器的消息不能是任意设置的选择键,必须是用小数点隔开的一系列的标识符.这些标识符可以是随意,但是通常跟消息的某些特性相关联.一些合法的路由选择键 ...

  5. 用BlockingQueue实现的简单发布订阅模式

  6. Go RabbitMQ(三)发布订阅模式

    RabbitMQ 在上一节中我们创建了工作队列,并且假设每一个任务都能够准确的到达对应的worker.在本节中我们将介绍如何将一个消息传递到多个消费者,这也就是所说的发布订阅模式 为了验证该模式我们使 ...

  7. RabbitMQ指南之三:发布/订阅模式(Publish/Subscribe)

    在上一章中,我们创建了一个工作队列,工作队列模式的设想是每一条消息只会被转发给一个消费者.本章将会讲解完全不一样的场景: 我们会把一个消息转发给多个消费者,这种模式称之为发布-订阅模式. 为了阐述这个 ...

  8. RabbitMQ六种队列模式-发布订阅模式

    前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅 [本文]RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...

  9. RabbitMQ学习第三记:发布/订阅模式(Publish/Subscribe)

    工作队列模式是直接在生产者与消费者里声明好一个队列,这种情况下消息只会对应同类型的消费者. 举个用户注册的列子:用户在注册完后一般都会发送消息通知用户注册成功(失败).如果在一个系统中,用户注册信息有 ...

随机推荐

  1. 关于shared_ptr与weak_ptr的使用(good)

    shared_ptr是带引用计数的智能指针,可以说大部分的情形选择用shared_ptr不会出问题.那么weak_ptr是什么,应该怎么用呢? weak_ptr也是智能指针,但是比较弱,感觉没什么用. ...

  2. 多态(instanceof)

    多态调用的三种格式 * A:多态的定义格式: * 就是父类的引用变量指向子类对象 父类类型 变量名 = new 子类类型(); 变量名.方法名(); * B: 普通类多态定义的格式 父类 变量名 = ...

  3. storm集群配置

    环境:centos6.4软件:jzmq-master-----java与c++通讯的桥梁,有了它,就可以使用zeromp了storm-0.8.2zeromq-2.1.7-----号称史上最牛逼的消息队 ...

  4. chrome浏览器安装不上的惨痛经历

    项目在赶进度的时候,手贱把chrome的一些文件删除了,整个浏览器都没法打开 决定重装下,但是连卸载的功能都打不开了 上网重新下载了个安装包,发现安装包都打不来 很绝望,查了很多资料 很多人说要删除注 ...

  5. C函数调用

    目录 C函数调用 设置SP SP分析 区分NAND和NOR启动 参数调用 title: C函数调用 tags: ARM date: 2018-10-14 16:37:10 --- C函数调用 设置SP ...

  6. java使用google开源工具实现图片压缩【转】

    jar包名 import net.coobird.thumbnailator.Thumbnails; import net.coobird.thumbnailator.geometry.Positio ...

  7. golang json反序列化

    package main import ( "encoding/json" "fmt" "reflect" ) type js struct ...

  8. mysql使用navicat和mysqldump导出数据

    1.navicat 方式一:选中表,右键转储:(含有表结构和数据) 方式二:选择右上角工具,点击数据传输,在这个页面右侧选择数据库,左侧选择文件. 点击下一步,选择导出的表名和各种函数什么的,然后点击 ...

  9. 解析ArcGis的标注(一)——先看看分数式、假分数式标注是怎样实现的

    该“标注”系列博文的标注引擎使用“标准标注引擎(standard label engine)”,这个概念如不知道,可不理会,ArcGis默认标注引擎就是它. ArcGis的标注表达式支持VBScrip ...

  10. 错误记录:vue跟vue编译器版本不一致

    错误如下: error in ./src/Utils.vue Module build failed: Error: Vue packages version mismatch: - vue@ - v ...