模型图

我们之前学习的都是一个消息只能被一个消费者消费,那么如果我想发一个消息 能被多个消费者消费,这时候怎么办? 这时候我们就得用到了消息中的发布订阅模型

在前面的教程中,我们创建了一个工作队列,都是一个任务只交给一个消费者。这次我们做 将消息发送给多个消费者。这种模式叫做“发布/订阅”。

举列:

类似微信订阅号 发布文章消息 就可以广播给所有的接收者。(订阅者)

那么咱们来看一下图,我们学过前两种有一些不一样,work 模式 是不是同一个队列 多个消费者,而 ps 这种模式呢,是一个队列对应一个消费者,pb 模式还多了一个 X(交换机 转发器) ,这时候我们要获取消息 就需要队列绑定到交换机上,交换机把消息发送到队列 , 消费者才能获取队列的消息

解读:
1、1 个生产者,多个消费者
2、每一个消费者都有自己的一个队列
3、生产者没有将消息直接发送到队列,而是发送到了交换机(转发器)
4、每个队列都要绑定到交换机
5、生产者发送的消息,经过交换机,到达队列,实现,一个消息被多个消费者获取的目的

生产者

 package cn.wh.simple;

 import java.io.IOException;
import java.util.concurrent.TimeoutException; import cn.wh.util.RabbitMqConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection; public class Send { private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException { Connection connection = RabbitMqConnectionUtil.getConnection(); Channel channel = connection.createChannel(); //声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");//分发 //发送消息
String msg="hello ps"; channel.basicPublish(EXCHANGE_NAME, "", null, msg.getBytes()); System.out.println("Send :"+msg); channel.close();
connection.close();
}
}

消费者1

 package cn.wh.simple;

 import java.io.IOException;
import java.util.concurrent.TimeoutException; import cn.wh.util.RabbitMqConnectionUtil; import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties; public class Recv1 { private static final String QUEUE_NAME="test_queue_fanout_email";
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMqConnectionUtil.getConnection();
final Channel channel = connection.createChannel(); //队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null); //绑定队列到交换机 转发器
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); channel.basicQos(1);//保证一次只分发一个 //定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException { String msg=new String(body,"utf-8");
System.out.println("[1] Recv msg:"+msg); try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[1] done ");
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
}; boolean autoAck=false;//自动应答 false
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}

消费者2

package cn.wh.simple;

import java.io.IOException;
import java.util.concurrent.TimeoutException; import cn.wh.util.RabbitMqConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties; public class Recv2 { private static final String QUEUE_NAME="test_queue_fanout_sms";
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMqConnectionUtil.getConnection();
final Channel channel = connection.createChannel(); //队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null); //绑定队列到交换机 转发器
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
channel.basicQos(1);//保证一次只分发一个 //定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException { String msg=new String(body,"utf-8");
System.out.println("[2] Recv msg:"+msg); try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[2] done ");
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
}; boolean autoAck=false;//自动应答 false
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}

测试

一个消息 可以被多个消费者

RabbitMQ 之 订阅模式 Publish/Subscribe的更多相关文章

  1. RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe)(转载)

    RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe) (本教程是使用Net客户端,也就是针对微软技术平台的) 在前一个教程中,我们创建了一个工作队列.工作队列背后的假设是每个 ...

  2. 观察者模式(Observer)和发布(Publish/订阅模式(Subscribe)的区别

    观察者模式(Observer)和发布(Publish/订阅模式(Subscribe)的区别 在翻阅资料的时候,有人把观察者(Observer)模式等同于发布(Publish)/订阅(Subscribe ...

  3. RabbitMQ(三) -- Publish/Subscribe

    RabbitMQ(三) -- Publish/Subscribe `rabbitmq`支持一对多的模式,一般称为发布/订阅.也就是说,生产者产生一条消息后,`rabbitmq`会把该消息分发给所有的消 ...

  4. RabbitMQ官方教程三 Publish/Subscribe(GOLANG语言实现)

    RabbitMQ官方教程三 Publish/Subscribe(GOLANG语言实现) 在上一个教程中,我们创建了一个工作队列. 工作队列背后的假设是,每个任务都恰好交付给一个worker处理. 在这 ...

  5. Mina、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)

    消息传递有很多种方式,请求/响应(Request/Reply)是最常用的.在前面的博文的例子中,很多都是采用请求/响应的方式,当服务器接收到消息后,会立即write回写一条消息到客户端.HTTP协议也 ...

  6. Mina、Netty、Twisted一起学(七):公布/订阅(Publish/Subscribe)

    消息传递有非常多种方式.请求/响应(Request/Reply)是最经常使用的.在前面的博文的样例中.非常多都是採用请求/响应的方式.当server接收到消息后,会马上write回写一条消息到clie ...

  7. 译: 3. RabbitMQ Spring AMQP 之 Publish/Subscribe 发布和订阅

    在第一篇教程中,我们展示了如何使用start.spring.io来利用Spring Initializr创建一个具有RabbitMQ starter dependency的项目来创建spring-am ...

  8. RabbitMQ入门:发布/订阅(Publish/Subscribe)

    在前面的两篇博客中 RabbitMQ入门:Hello RabbitMQ 代码实例 RabbitMQ入门:工作队列(Work Queue) 遇到的实例都是一个消息只发送给一个消费者(工作者),他们的消息 ...

  9. 【译】RabbitMQ:发布-订阅(Publish/Subscribe)

    在前一篇教程中,我们创建了一个工作队列,我们假设在工作队列后的每一个任务都只被调度给一个消费者.在这一部分,我们将做一些完全不一样的事情,调度同一条消息给多个消费者,也就是有名的“发布-订阅”模式.为 ...

随机推荐

  1. SSO详解(转)

    转自:http://www.cnblogs.com/EzrealLiu/p/5559255.html 1. 摘要 SSO这一概念由来已久,网络上对应不同场景的成熟SSO解决方案比比皆是,从简单到复杂, ...

  2. 浅谈pipreqs组件(自动生成需要导入的模块信息)

    简介 pipreqs的作用 一起开发项目的时候总是要搭建环境和部署环境的,这个时候必须得有个python第三方包的list,一般都叫做requirements.txt. 如果一个项目使用时virtua ...

  3. Flask蓝图,Session,闪现,中间件等

    Session 除请求对象之外,还有一个 session 对象.它允许你在不同请求间存储特定用户的信息.它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设 ...

  4. Python中字符串拼接的N种方法

    python拼接字符串一般有以下几种方法: ①直接通过(+)操作符拼接 s = 'Hello'+' '+'World'+'!'print(s) 输出结果:Hello World! 使用这种方式进行字符 ...

  5. 部署knight项目

    发布CRM你将使用以下软件 nginx uWSGI CentOS7 CRM项目文件 virtualenv supervisor WSGI.uWSGI python web服务器开发使用WSGI协议(W ...

  6. java_基础——用代码编译.java文件+加载class文件

    [本文介绍] 本文不是深入理解和使用java编译器,只是在代码里编译.java文件的helloWorld.这种技术还是蛮有意思的,说不定在将来的某些只能化项目会运用到!^_^ [简单编译的流程] [j ...

  7. 006-Shell printf 命令

    一.概述 printf 命令模仿 C 程序库(library)里的 printf() 程序. printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好. pr ...

  8. Android training–android studio

    又重新开始学习android开发了,希望这次不是三分钟热度.之前是利用eclipse+ADT来开发的,官网上建议用Android Studio.刚好重装了系统,升级了内存.于是下个studio来学学. ...

  9. Avocado 安装和简单测试

    1.Avocado 安装 1.1 通过包安装 像Fedora可以通过rpm包进行安装,其他通过RPM管理的发行版需要自己制作相关包.Avocado同样支持DEP包的安装可以在contrib/packa ...

  10. python全栈开发从入门到放弃之常用模块和正则

    什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的代码(.p ...