RabbitMQ简单应用の订阅模式
订阅模式
公众号-->订阅之后才会收到相应的文章。
解读:
1.一个生产者,多个消费者
2.每个消费者都有自己的队列
3.生产者没有将消息直接发送到队列里,而是发送给了交换机(转发器)exchange
4.每个队列都要绑定到交换机(转发器)上
5.生产者发送的消息记过交换机然后到达队列,然后就能实现被多个消费者消费
图例:
|-------------|-----Q-----C3
P------------X-------------|-----Q-----C3
|-------------|-----Q-----C3
注册--->发邮件--->发短信
MQ工厂类Connection
package com.mmr.rabbitmq.util; import java.io.IOException; import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; public class ConnectionUtils {
/**
* @desc 获取Mq 的链接
* @author zp
* @throws IOException
* @date 2018-7-19
*/
public static Connection getConnection() throws IOException {
// 1.定义一个链接工厂
ConnectionFactory factroy = new ConnectionFactory(); // 2.设置服务地址
factroy.setHost("127.0.0.1"); // 3.设置端口号
factroy.setPort(5672); // 4.vhost 设置数据库
factroy.setVirtualHost("vhtest"); // 5.设置用户名
factroy.setUsername("jerry"); // 6. 设置密码
factroy.setPassword("123456"); // 7.返回链接
return factroy.newConnection();
}
}
消息生产者类Send,这个时候,运行代码再到控制台去查看,并没有发现我们的消息,因为在MQ中只有队列可以存储消息,而交换机不可以存储消息,下面这段代码并没有将交换机和队列进行绑定,所以数据就丢失了。
package com.mmr.rabbitmq.ps; import java.io.IOException; import com.mmr.rabbitmq.util.ConnectionUtils;
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 {
// 创建连接
Connection connection = ConnectionUtils.getConnection(); // 获取通道
Channel channel = connection.createChannel(); // 声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");// fanout 分发 // 发送消息
String msg = "hello ps"; channel.basicPublish(EXCHANGE_NAME, "", null, msg.getBytes());
System.out.println("send:"+msg);
channel.close();
connection.close(); }
}
代码运行后的控制台:
由于交换机不能存储数据,那么我们就需要考虑如何将交换机和队列进行绑定。因为只要将两者进行绑定之后,那么数据存储问题就迎刃而解。
消费者Recv1 Recv2
package com.mmr.rabbitmq.ps; import java.io.IOException; import com.mmr.rabbitmq.util.ConnectionUtils;
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_STRING="test_queue_fanout_email";
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException {
// 创建连接
Connection connection = ConnectionUtils.getConnection(); // 创建通道
final Channel channel = connection.createChannel(); // 声明队列
channel.queueDeclare(QUEUE_NAME_STRING, false, false, false, null); // 绑定队列,绑定到交换机/转发器
channel.queueBind(QUEUE_NAME_STRING, EXCHANGE_NAME, ""); // 保证每次只分发一个
channel.basicQos(1); // 定义一个消费者
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
// TODO Auto-generated method stub
String msg = new String(body,"utf-8");
System.out.println("[1]Recv msg:"+msg);
try {
// 每次休息一会儿
Thread.sleep(2000);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally{
System.out.println("recv1 done");
//回执
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
boolean autoAck = false;// 不自动应答
channel.basicConsume(QUEUE_NAME_STRING, autoAck,consumer); }
}
package com.mmr.rabbitmq.ps; import java.io.IOException; import com.mmr.rabbitmq.util.ConnectionUtils;
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_STRING="test_queue_fanout_sms";
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException {
// 创建连接
Connection connection = ConnectionUtils.getConnection(); // 创建通道
final Channel channel = connection.createChannel(); // 声明队列
channel.queueDeclare(QUEUE_NAME_STRING, false, false, false, null); // 绑定队列,绑定到交换机/转发器
channel.queueBind(QUEUE_NAME_STRING, EXCHANGE_NAME, ""); // 保证每次只分发一个
channel.basicQos(1); // 定义一个消费者
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
// TODO Auto-generated method stub
String msg = new String(body,"utf-8");
System.out.println("[2]Recv msg:"+msg);
try {
// 每次休息一会儿
Thread.sleep(2000);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally{
System.out.println("recv2 done");
//回执
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
boolean autoAck = false;// 不自动应答
channel.basicConsume(QUEUE_NAME_STRING, autoAck,consumer); }
}
运行上述代码进行监听,再通过运行Send发送消息,我们可以在MQ-管理平台上看到:
进过这样的使用,我们的消息订阅就完成了。
RabbitMQ简单应用の订阅模式的更多相关文章
- RabbitMQ的发布订阅模式(Publish/Subscribe)
一.发布/订阅(Publish/Subscribe)模式 发布订阅是我们经常会用到的一种模式,生产者生产消息后,所有订阅者都可以收到.RabbitMQ的发布/订阅模型图如下: 1.该模式下生产者并不是 ...
- RabbitMQ入门-消息订阅模式
消息派发 上篇<RabbitMQ入门-消息派发那些事儿>发布之后,收了不少反馈,其中问的最多的还是有关消息确认以及超时等场景的处理. 楼主,有遇到消费者后台进程不在,但consumer连接 ...
- RabbitMQ入门-发布订阅模式
兔子的Publish/Subscribe是这样的: 有个生产者P,X代表交换机,交换机绑定队列,消费者从队列中取得消息.每次有消息,先发到交换机中,然后由交换机负责发送到它已知的队列中. 生产者代码: ...
- RabbitMQ简单应用の主题模式(topic)
Topic exchange(主题转发器) 发送给主题转发器的消息不能是任意设置的选择键,必须是用小数点隔开的一系列的标识符.这些标识符可以是随意,但是通常跟消息的某些特性相关联.一些合法的路由选择键 ...
- 用BlockingQueue实现的简单发布订阅模式
- Go RabbitMQ(三)发布订阅模式
RabbitMQ 在上一节中我们创建了工作队列,并且假设每一个任务都能够准确的到达对应的worker.在本节中我们将介绍如何将一个消息传递到多个消费者,这也就是所说的发布订阅模式 为了验证该模式我们使 ...
- RabbitMQ指南之三:发布/订阅模式(Publish/Subscribe)
在上一章中,我们创建了一个工作队列,工作队列模式的设想是每一条消息只会被转发给一个消费者.本章将会讲解完全不一样的场景: 我们会把一个消息转发给多个消费者,这种模式称之为发布-订阅模式. 为了阐述这个 ...
- RabbitMQ六种队列模式-发布订阅模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅 [本文]RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...
- RabbitMQ学习第三记:发布/订阅模式(Publish/Subscribe)
工作队列模式是直接在生产者与消费者里声明好一个队列,这种情况下消息只会对应同类型的消费者. 举个用户注册的列子:用户在注册完后一般都会发送消息通知用户注册成功(失败).如果在一个系统中,用户注册信息有 ...
随机推荐
- 关键字(2):循环和分支结构for/while/loop/switch
FOR i IN tRange1.first .. tRange1.last LOOP IF Instr(CardNum, tRange1(i), ) = THEN GLOBAL_VARBLE.nPo ...
- c3p0配置Spring
jdbc.properties jdbcUrl=jdbc:mysql://localhost:3306/myoa?useUnicode=true&characterEncoding=utf-8 ...
- ATPCS规则
title: ATPCS规则 tags: ARM date: 2018-10-14 17:03:23 --- ATPCS规则 ARM指令集E004armproc.chm ATPCS介绍与使用.pdf ...
- js中Date与timestamp(时间戳)的相互转换
#时间(Date)转时间戳(Timestamp): 1.var timestamp1 = (new Date()).valueOf(); // 结果:1535374762785,通过valueOf() ...
- zookeeper安装(集群)
Dubbo 建议使用Zookeeper 作为服务的注册中心.Zookeeper 集群中只要有过半的节点是正常的情况下,那么整个集群对外就是可用的.正是基于这个特性,要将ZK 集群的节点数量要为奇数(2 ...
- jenkins笔记
java -jar jenkins.war -httpPort=9090 以9090端口启动jekins的web应用(内置jetty)
- golang json反序列化
package main import ( "encoding/json" "fmt" "reflect" ) type js struct ...
- IntelliJ IDEA(2017)安装和破解
IDEA 全称 IntelliJ IDEA,是Java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手.代码自动提示.重构.J2EE支持.各类版本工具( ...
- 在py文件中设置文件头
在写python文件的时候有时需要记录作者.创建时间等时间,因此可以给python文件设置文件头,这里以PyCharm为例介绍设置步骤: 1. 打开PyCharm,依次点击Setting-----Ed ...
- 我的长大app开发教程第二弹:完成ContentFragment底部按钮
在开始之前,先上一张效果图 突然发现有点知乎的味道...的确..知乎灰#989898,知乎蓝15,136,235(逃.... 1.学P图 想我大一的时候也用过不少Adobe的软件,昨天重新打开我的Ph ...