3.rabbitmq--发布订阅模式
rabbitmq-----发布订阅模式
模型组成
一个消费者Producer,一个交换机Exchange,多个消息队列Queue,多个消费者Consumer
一个生产者,多个消费者,每一个消费者都有自己的一个队列,生产者没有将消息直接发送到队列,而是发送到了交换机,每个队列绑定交换机,生产者发送的消息经过交换机,到达队列,实现一个消息被多个消费者获取的目的。需要注意的是,如果将消息发送到一个没有队列绑定的exchange上面,那么该消息将会丢失,这是因为在rabbitMQ中exchange不具备存储消息的能力,只有队列具备存储消息的能力。


Exchange
相比较于前两种模型Hello World和Work,这里多一个一个Exchange。其实Exchange是RabbitMQ的标配组成部件之一,前两种没有提到Exchange是为了简化模型,即使模型中没有看到Exchange的声明,其实还是声明了一个默认的Exchange。
RabbitMQ中实际发送消息并不是直接将消息发送给消息队列,消息队列也没那么聪明知道这条消息从哪来要到哪去。RabbitMQ会先将消息发送个Exchange,Exchange会根据这条消息打上的标记知道该条消息从哪来到哪去。
Exchange凭什么知道消息的何去何从,因为Exchange有几种类型:direct,fanout,topic和headers。这里说的订阅者模式就可以认为是fanout模式了。
RabbitMQ中,所有生产者提交的消息都由Exchange来接受,然后Exchange按照特定的策略转发到Queue进行存储 RabbitMQ提供了四种Exchange:fanout,direct,topic,header .发布/订阅模式就是是基于fanout Exchange实现的。
fanout这种模式不需要指定队列名称,需要将Exchange和queue绑定,他们之间的关系是‘多对多’的关系
任何发送到fanout Exchange的消息都会被转发到与该Exchange绑定的queue上面。
订阅者模式有何不同
订阅者模式相对前面的Work模式有和不同?Work也有多个消费者,但是只有一个消息队列,并且一个消息只会被某一个消费者消费。但是订阅者模式不一样,它有多个消息队列,也有多个消费者,而且一条消息可以被多个消费者消费,类似广播模式。下面通过实例代码看看这种模式是如何收发消息的。
package com.maozw.mq.pubsub; import com.maozw.mq.config.RabbitConfig;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.io.IOException;
import java.util.concurrent.TimeoutException; import static org.apache.log4j.varia.ExternallyRolledFileAppender.OK; /**
* work 模式
* 两种分发: 轮询分发 + 公平分发
* 轮询分发:消费端:自动确认消息;boolean autoAck = true;
* 公平分发: 消费端:手动确认消息 boolean autoAck = false; channel.basicAck(envelope.getDeliveryTag(),false);
*
* @author MAOZW
* @Description: ${todo}
* @date 2018/11/26 15:06
*/
@RestController
@RequestMapping("/publish")
public class PublishProducer {
private static final Logger LOGGER = LoggerFactory.getLogger(PublishProducer.class);
@Autowired
RabbitConfig rabbitConfig; @RequestMapping("/send/{exchangeName}/{queueName}")
public String send(@PathVariable String exchangeName, @PathVariable String queueName) throws IOException, TimeoutException {
Connection connection = null;
Channel channel= null;
try {
ConnectionFactory connectionFactory = rabbitConfig.connectionFactory();
connection = connectionFactory.createConnection();
channel = connection.createChannel(false); /**
* 申明交换机
*/
channel.exchangeDeclare(exchangeName,"fanout"); /**
* 发送消息
* 每个消费者 发送确认消息之前,消息队列不会发送下一个消息给消费者,一次只处理一个消息
* 自动模式无需设置下面设置
*/
int prefetchCount = ;
channel.basicQos(prefetchCount); String Hello = ">>>> Hello Simple <<<<";
for (int i = ; i < ; i++) {
String message = Hello + i;
channel.basicPublish(RabbitConfig.EXCHANGE_AAAAA, "", null, message.getBytes());
LOGGER.info("生产消息: " + message);
}
return "OK";
}catch (Exception e) { } finally {
connection.close();
channel.close();
return OK;
}
}
}
订阅1
package com.maozw.mq.pubsub; import com.maozw.mq.config.RabbitConfig;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory; import java.io.IOException; /**
* @author MAOZW
* @Description: ${todo}
* @date 2018/11/26 15:06
*/ public class SubscribeConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(SubscribeConsumer.class); public static void main(String[] args) throws IOException {
ConnectionFactory connectionFactory = RabbitConfig.getConnectionFactory();
Connection connection = connectionFactory.createConnection();
Channel channel = connection.createChannel(false);
/**
* 创建队列申明
*/
boolean durable = true;
channel.queueDeclare(RabbitConfig.QUEUE_PUBSUB_FANOUT, durable, false, false, null);
/**
* 绑定队列到交换机
*/
channel.queueBind(RabbitConfig.QUEUE_PUBSUB_FANOUT, RabbitConfig.EXCHANGE_AAAAA,""); /**
* 改变分发规则
*/
channel.basicQos(1);
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);
System.out.println("[2] 接口数据 : " + new String(body, "utf-8"));
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[2] done!");
//消息应答:手动回执,手动确认消息
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//监听队列
/**
* autoAck 消息应答
* 默认轮询分发打开:true :这种模式一旦rabbitmq将消息发送给消费者,就会从内存中删除该消息,不关心客户端是否消费正常。
* 使用公平分发需要关闭autoAck:false 需要手动发送回执
*/
boolean autoAck = false;
channel.basicConsume(RabbitConfig.QUEUE_PUBSUB_FANOUT,autoAck, consumer);
} }
package com.maozw.mq.pubsub; import com.maozw.mq.config.RabbitConfig;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory; import java.io.IOException; /**
* @author MAOZW
* @Description: ${todo}
* @date 2018/11/26 15:06
*/ public class SubscribeConsumer2 {
private static final Logger LOGGER = LoggerFactory.getLogger(SubscribeConsumer2.class); public static void main(String[] args) throws IOException {
ConnectionFactory connectionFactory = RabbitConfig.getConnectionFactory();
Connection connection = connectionFactory.createConnection();
Channel channel = connection.createChannel(false);
/**
* 创建队列申明
*/
boolean durable = true;
channel.queueDeclare(RabbitConfig.QUEUE_PUBSUB_FANOUT2, durable, false, false, null);
/**
* 绑定队列到交换机
*/
channel.queueBind(RabbitConfig.QUEUE_PUBSUB_FANOUT2, RabbitConfig.EXCHANGE_AAAAA,""); /**
* 改变分发规则
*/
channel.basicQos(1);
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);
System.out.println("[2] 接口数据 : " + new String(body, "utf-8"));
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[2] done!");
//消息应答:手动回执,手动确认消息
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//监听队列
/**
* autoAck 消息应答
* 默认轮询分发打开:true :这种模式一旦rabbitmq将消息发送给消费者,就会从内存中删除该消息,不关心客户端是否消费正常。
* 使用公平分发需要关闭autoAck:false 需要手动发送回执
*/
boolean autoAck = false;
channel.basicConsume(RabbitConfig.QUEUE_PUBSUB_FANOUT2,autoAck, consumer);
}
}
3.rabbitmq--发布订阅模式的更多相关文章
- .Net下RabbitMQ发布订阅模式实践
一.概念AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计.消息中间件主要用于组件之间的解耦,消息的发 ...
- RabbitMQ 发布订阅
互联网公司对消息队列是深度使用者,因此需要我们了解消息队列的方方面面,良好的设计及深入的理解,更有利于我们对消息队列的规划. 当前我们使用消息队列中发现一些问题: 1.实际上是异步无返回远程调用,由发 ...
- RabbitMQ/JAVA (发布/订阅模式)
发布/订阅模式即生产者将消息发送给多个消费者. 下面介绍几个在发布/订阅模式中的关键概念-- 1. Exchanges (转发器) 可能原来我们都是基于一个队列发送和接收消息.现在介绍一下完整的消息传 ...
- python使用rabbitMQ介绍三(发布订阅模式)
一.模式介绍 在前面的例子中,消息直接发送到queue中. 现在介绍的模式,消息发送到exchange中,消费者把队列绑定到exchange上. 发布-订阅模式是把消息广播到每个消费者,每个消费者接收 ...
- Go RabbitMQ(三)发布订阅模式
RabbitMQ 在上一节中我们创建了工作队列,并且假设每一个任务都能够准确的到达对应的worker.在本节中我们将介绍如何将一个消息传递到多个消费者,这也就是所说的发布订阅模式 为了验证该模式我们使 ...
- RabbitMQ指南之三:发布/订阅模式(Publish/Subscribe)
在上一章中,我们创建了一个工作队列,工作队列模式的设想是每一条消息只会被转发给一个消费者.本章将会讲解完全不一样的场景: 我们会把一个消息转发给多个消费者,这种模式称之为发布-订阅模式. 为了阐述这个 ...
- RabbitMQ六种队列模式-发布订阅模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅 [本文]RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...
- RabbitMQ入门学习系列(四) 发布订阅模式
发布订阅模式 什么时发布订阅模式 把消息发送给多个订阅者.也就是有多个消费端都完整的接收生产者的消息 换句话说 把消息广播给多个消费者 消息模型的核心 RabbitMQ不发送消息给队列,生产者也不知道 ...
- RabbitMQ学习第三记:发布/订阅模式(Publish/Subscribe)
工作队列模式是直接在生产者与消费者里声明好一个队列,这种情况下消息只会对应同类型的消费者. 举个用户注册的列子:用户在注册完后一般都会发送消息通知用户注册成功(失败).如果在一个系统中,用户注册信息有 ...
- 4.RabbitMQ系列之发布/订阅模式
我们把一个消息转发给多个消费者,这种模式称之为发布-订阅模式 1.交换器(Exchange) RabbitMq消息模式的核心思想是:一个生产者并不会直接往一个队列中发送消息,事实上,生产者根本不知道它 ...
随机推荐
- PHP如何通过URL访问,获得新的URL 两种方法
1.1 $url = 'http://passport.drcloud.cn/api/logon.asp?id=1&ru=http://203.158.158.122/store/thirdL ...
- mvc控制器返回操作结果封装
实体类 public class AjaxResult { /// <summary> /// 获取 Ajax操作结果类型 /// </summary> public Resu ...
- Springboot+mybatis+druid 配置多数据源
项目结构 application.yml配置文件 spring: application: name: service datasource: primary: jdbc-url: jdbc:orac ...
- YoloV3 训练崩溃
经过排查 发现是这里出了问题 然后发现是标注文件里有 x=0 y=0 这样的数据,46_Jockey_Jockey_46_576.txt , 那么肯定是标注文件出了问题!! 删除该标注文件即可. ...
- 微信小程序跳到指定页面不生效
wx.redirectTo({ url: './index', }) wx.navigateTo({ url: './index', }) 用了这两种都没生效,点击没跳转,也没报错 后来想了下是不是因 ...
- 1.JavaWeb 知识点概览
1.tomcat服务器的安装和配置.http协议 1.1 虚拟目录的 /*映射*/(配置Context元素)(server.xml catalina\localhost\) http://blog.c ...
- Linux磁盘的管理
文件系统 磁盘必须要有文件系统---数据库 文件系统是用来数据存储,数据库是用来管理数据 windows fat32 ntfs exfat linux 单文件系统 inode--索引空间(文件 ...
- (十一)tina | openwrt关闭调试串口(DEBUG UART)
//编辑以下文件 vi target/allwinner/astar-parrot/base-files/etc/inittab //不同系统文件路径注意更改 //文件内容如下,注释::askcon ...
- 013.子查询和分页子查询(sql实例)
--1 子查询 如果子查询和表连接都实现的时候,推荐用表连接实现( 一般:能用表连接实现的就用表连接,有些情况用表连接不能 或者不易实现的再选择子查询) 系统:缓存,执行计划技术手段 --1 wher ...
- Hadoop_19_MapReduce&&Yarn运行机制
1.YARN的运行机制 1.1.概述: Yarn集群:负责海量数据运算时的资源调度,集群中的角色主要有:ResourceManager.NodeManager Yarn是一个资源调度(作业调度和集群资 ...