1. 初识RabbitMQ

RabbitMQ 是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用 Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的

RabbitMQ的优点:

  • 开源、性能优秀、稳定性保障
  • 提供可靠性消息投递模式(confirm)、返回模式(return)
  • 与SpringAMQP完美的整合、API丰富
  • 集群模式丰富,表达式配置,HA模式,镜像队列模型
  • 保证数据不丢失的前提下做到高可靠性、可用性

RabbitMQ官网

RabbitMQ的整体架构:

 

RabbitMQ的消息流转:

 

 

2. AMQP

AMQP全称: Advanced Message Queuing Protocol

AMQP翻译: 高级消息队列协议

AMQP定义:是具有现代特征的二进制协议。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计

 

 

AMQP核心概念:

  • Server:又称Broker,接受客户端的连接,实现AMQP实体服务
  • Connection:连接,应用程序与Broker的网络连接
  • Channel:网络信道,几乎所有的操作都在Channel中进行,Channel是进行消息读写的通道。客户端可建立多个Channel,每个Channel代表一个会话任务
  • Message:消息,服务器和应用程序之间传送的数据,由Properties和Body组成。Properties可以对消息进行修饰,比如消息的优先级、延迟等高级特性;Body则是消息体的内容
  • Virtual host:虚拟地址,用于进行逻辑隔离,最上层的消息路由。同一个Virtual Host里面不能有相同名称的Exchange或Queue
  • Exchange:交换机,接收消息,根据路由键转发消息到绑定的队列
  • Binding:Exchange和Queue之间的虚拟连接,binding中可以包含routing key
  • Routing key:一个路由规则,虚拟机可用它确定如何路由一个特定消息
  • Queue:也称为Message Queue,消息队列,保存消息并将它们转发给消费者

 

 

3.RabbitMQ的极速入门

后台启动: ./rabbitmq start &

关闭: ./rabbitmqctl stop

节点状态: ./rabbitmqctl status

管控台: http://ip:15672

 

 

RabbitMQ生产消费快速入门:

环境: springboot+jdk1.7+rabbitmq3.6.5 (Maven依赖配置)

 <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.6.5</version>
</dependency>
</dependencies>

 

public class Procuder {
public static void main(String[] args) throws Exception { //1.创建一个ConnectionFactory 并进行配置
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setHandshakeTimeout(20000);
//2.通过连接工厂创建连接
Connection connection = connectionFactory.newConnection(); //3.通过Connection 创建一个 Channel
Channel channel = connection.createChannel(); /**
* basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
* exchange:指定交换机 不指定 则默认 (AMQP default交换机) 通过routingkey进行匹配
* props 消息属性
* body 消息体
*/
//4.通过Channel发送数据
for(int i = 0; i < 5; i++){
System.out.println("生产消息:" + i);
String msg = "Hello RabbitMQ" + i;
channel.basicPublish("", "test", null, msg.getBytes());
} //5.记得关闭相关的连接
channel.close();
connection.close();
}
}

 

public class Consumer {
public static void main(String[] args) throws Exception{
//1.创建一个ConnectionFactory 并进行配置
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setHandshakeTimeout(20000);
//2.通过连接工厂创建连接
Connection connection = connectionFactory.newConnection(); //3.通过Connection 创建一个 Channel
Channel channel = connection.createChannel(); //4. 声明创建一个队列
String queueName = "test";
/**
* durable 是否持久化
* exclusive 独占的 相当于加了一把锁
*/
channel.queueDeclare(queueName,true,false,false,null); //5.创建消费者
QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //6.设置channel
/**
* ACK: 当一条消息从生产端发到消费端,消费端接收到消息后会马上回送一个ACK信息给broker,告诉它这条消息收到了
* autoack:
* true 自动签收 当消费者一收到消息就表示消费者收到了消息,消费者收到了消息就会立即从队列中删除。
* false 手动签收 当消费者收到消息在合适的时候来显示的进行确认,说我已经接收到了该消息了,RabbitMQ可以从队列中删除该消息了
*
*/
channel.basicConsume(queueName, true, queueingConsumer); //7.获取消息
while(true){
Delivery delivery = queueingConsumer.nextDelivery();
String msg = new String(delivery.getBody());
System.err.println("消费端:" + msg);
//Envelope envelope = delivery.getEnvelope();
}
}
}

 

4. Exchange(交换机)详解

Exchange: 接收消息,并根据路由键转发消息所绑定的队列

 

交换机属性:

  • Name: 交换机名称
  • Type: 交换机类型 diect、topic、fanout、headers
  • Durability:是否需要持久化,true为持久化
  • AutoDelete: 当最后一个绑定到Exchange的队列删除后,自动删除该Exchange
  • Internal: 当前Exchange是否用于RabbitMQ内部使用,默认为false (百分之99的情况默认为false 除非对Erlang语言较了解,做一些扩展)
  • Arguments:扩展参数, 用于扩展AMQP协议可自定化使用

 

4.1 Direct Exchange

所有发送到Direct Exchange的消息被转发到RouteKey指定的Queue

注意:Direct模式可以使用RabbitMQ自带的Exchange: default Exchange,所以不需要将Exchange进行任何绑定(binding)操作,消息传递时,RoutingKey必须完全匹配才会被队列接收,否则该消息会被抛弃

 

public class ProducerDirectExchange {
public static void main(String[] args) throws Exception {
//1.创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/"); //2.创建Connection
Connection connection = connectionFactory.newConnection();
//3.创建Channel
Channel channel = connection.createChannel();
//4.声明
String exchangeName = "test_direct_exchange";
String routingKey = "test.direct";
//5.发送
String msg = "Hello World RabbitMQ4 Direct Exchange Message";
channel.basicPublish(exchangeName, routingKey, null, msg.getBytes());
}
}

 

public class ConsumerDirectExchange {
public static void main(String[] args) throws Exception{
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setHandshakeTimeout(20000);
connectionFactory.setAutomaticRecoveryEnabled(true);
connectionFactory.setNetworkRecoveryInterval(3000); Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel();
//声明
String exchangeName = "test_direct_exchange";
String exchangeType = "direct";
String queueName = "test_direct_queue";
String routingKey = "test.direct";
//表示声明了一个交换机
channel.exchangeDeclare(exchangeName, exchangeType,true,false,false,null);
//表示声明了一个队列
channel.queueDeclare(queueName,false,false,false,null);
//建立一个绑定关系
channel.queueBind(queueName, exchangeName, routingKey); //durable 是否持久化消息
QueueingConsumer consumer = new QueueingConsumer(channel);
//参数:队列名称,是否自动ACK,Consumer
channel.basicConsume(queueName, true, consumer); //循环获取消息
while(true){
//获取消息,如果没有消息,这一步将会一直阻塞
Delivery delivery = consumer.nextDelivery();
String msg = new String(delivery.getBody());
System.out.println("收到消息:" + msg);
}
}
}

 

4.2 Topic Exchange

所有发送到Topic Exchange的消息被转发到所有关心RouteKey中指定Topic的Queue上

Exchange将RouteKey和某Topic进行模糊匹配,此时队列需要绑定一个Topic

注意:可以使用通配符进行匹配

符号 # 匹配一个或多个词

符号 * 匹配不多不少一个词

例如: "log.#" 能够匹配到 “log.info.oa”

​ "log.*" 只会匹配到 "log.err"

public class ProducerTopicExchange {
public static void main(String[] args) throws Exception {
//1.创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setHandshakeTimeout(20000); //2.创建Connection
Connection connection = connectionFactory.newConnection();
//3.创建Channel
Channel channel = connection.createChannel();
//4.声明
String exchangeName = "test_topic_exchange";
String routingKey1 = "user.save";
String routingKey2 = "user.update";
String routingKey3 = "user.delete.abc";
//5.发送
String msg = "Hello World RabbitMQ4 Direct Exchange Message";
channel.basicPublish(exchangeName, routingKey1, null, msg.getBytes());
channel.basicPublish(exchangeName, routingKey2, null, msg.getBytes());
channel.basicPublish(exchangeName, routingKey3, null, msg.getBytes());
}
}

 

public class ConsumerTopicExchange {
public static void main(String[] args) throws Exception{
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setHandshakeTimeout(20000);
connectionFactory.setAutomaticRecoveryEnabled(true);
connectionFactory.setNetworkRecoveryInterval(3000); Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel();
//声明
String exchangeName = "test_topic_exchange";
String exchangeType = "topic";
String queueName = "test_topic_queue";
String routingKey = "user.#";
//表示声明了一个交换机
channel.exchangeDeclare(exchangeName, exchangeType,true,false,false,null);
//表示声明了一个队列
channel.queueDeclare(queueName,false,false,false,null);
//建立一个绑定关系
channel.queueBind(queueName, exchangeName, routingKey); //durable 是否持久化消息
QueueingConsumer consumer = new QueueingConsumer(channel);
//参数:队列名称,是否自动ACK,Consumer
channel.basicConsume(queueName, true, consumer); //循环获取消息
while(true){
//获取消息,如果没有消息,这一步将会一直阻塞
Delivery delivery = consumer.nextDelivery();
String msg = new String(delivery.getBody());
System.out.println("收到消息:" + msg);
}
}
}

 

4.3 Fanout Exchange

不处理路由键,只需要简单的将队列绑定到交换机上

发送到交换机的消息都会被转发到与该交换机绑定的所有队列上

所以Fanout交换机转发消息是最快的

 

public class ProducerFanoutExchange {
public static void main(String[] args) throws Exception {
//1.创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setHandshakeTimeout(20000); //2.创建Connection
Connection connection = connectionFactory.newConnection();
//3.创建Channel
Channel channel = connection.createChannel();
//4.声明
String exchangeName = "test_fanout_exchange";
//5.发送
for(int i = 0; i < 10 ; i++){
String msg = "Hello World RabbitMQ4 Direct Exchange Message";
channel.basicPublish(exchangeName, "", null, msg.getBytes());
}
channel.close();
connection.close();
}
}

 

public class ConsumerFanoutExchange {
public static void main(String[] args) throws Exception{
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setHandshakeTimeout(20000);
connectionFactory.setAutomaticRecoveryEnabled(true);
connectionFactory.setNetworkRecoveryInterval(3000); Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel();
//声明
String exchangeName = "test_fanout_exchange";
String exchangeType = "fanout";
String queueName = "test_topic_queue";
//无需指定路由key
String routingKey = "";
//表示声明了一个交换机
channel.exchangeDeclare(exchangeName, exchangeType,true,false,false,null);
//表示声明了一个队列
channel.queueDeclare(queueName,false,false,false,null);
//建立一个绑定关系
channel.queueBind(queueName, exchangeName, routingKey); //durable 是否持久化消息
QueueingConsumer consumer = new QueueingConsumer(channel);
//参数:队列名称,是否自动ACK,Consumer
channel.basicConsume(queueName, true, consumer); //循环获取消息
while(true){
//获取消息,如果没有消息,这一步将会一直阻塞
Delivery delivery = consumer.nextDelivery();
String msg = new String(delivery.getBody());
System.out.println("收到消息:" + msg);
}
}
}

 

5. Message 消息

服务器与应用程序之间传递的数据,本质上就是一段数据,由Properties和Body组成

常用属性:delivery mode、headers (自定义属性)

其他属性:content_type、content_encoding、priority、expiration

消息的properties属性用法示例:

public class Procuder {
public static void main(String[] args) throws Exception { //1.创建一个ConnectionFactory 并进行配置
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setHandshakeTimeout(20000);
//2.通过连接工厂创建连接
Connection connection = connectionFactory.newConnection(); //3.通过Connection 创建一个 Channel
Channel channel = connection.createChannel(); Map<String,Object> headers = new HashMap<>();
headers.put("my1", "111");
headers.put("my2", "222"); //10秒不消费 消息过期移除消息队列
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder()
.deliveryMode(2)
.contentEncoding("utf-8")
.expiration("10000")
.headers(headers)
.build(); //4.通过Channel发送数据
for(int i = 0; i < 5; i++){
System.out.println("生产消息:" + i);
String msg = "Hello RabbitMQ" + i;
channel.basicPublish("", "test", properties, msg.getBytes());
} //5.记得关闭相关的连接
channel.close();
connection.close();
}
}

 

public class Consumer {
public static void main(String[] args) throws Exception{
//1.创建一个ConnectionFactory 并进行配置
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.244.11");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setHandshakeTimeout(20000);
//2.通过连接工厂创建连接
Connection connection = connectionFactory.newConnection(); //3.通过Connection 创建一个 Channel
Channel channel = connection.createChannel(); //4. 声明创建一个队列
String queueName = "test";
channel.queueDeclare(queueName,true,false,false,null); //5.创建消费者
QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //6.设置channel
channel.basicConsume(queueName, true, queueingConsumer); //7.获取消息
while(true){
Delivery delivery = queueingConsumer.nextDelivery();
String msg = new String(delivery.getBody());
System.err.println("消费端:" + msg); Map<String, Object> headers = delivery.getProperties().getHeaders();
System.err.println("headers value:" + headers.get("my1"));
}
}
}

RabbitMQ 从入门到精通 (一)的更多相关文章

  1. RabbitMQ从入门到精通

    RabbitMQ从入门到精通 学习了:http://blog.csdn.net/column/details/rabbitmq.html RabbitMQ是AMQP(advanced message ...

  2. RabbitMQ 从入门到精通(二)

    目录 1. 消息如何保障百分之百的投递成功? 1.1 方案一:消息落库,对消息状态进行打标 1.2 方案二:消息的延迟投递,做二次确认,回调检查 2. 幂等性 2.1 幂等性是什么? 2.2 消息端幂 ...

  3. RabbitMQ从入门到精通(三)

    目录 1. 自定义消费者使用 自定义消费端演示 2.消费端的限流策略 2.1 限流的场景与机制 2.2 限流相关API 2.3 限流演示 3. 消费端ACK与重回队列机制 3.1 ACK与NACK 3 ...

  4. 微博,and java 多线程编程 入门到精通 将cpu 的那个 张振华

    http://down.51cto.com/data/2263476  java 多线程编程 入门到精通  将cpu 的那个 张振华 多个用户可以同时用一个 vhost,但是vhost之间是隔离的. ...

  5. <程序员从入门到精通> -- How

    定位 自己才是职业生涯的管理者,想清楚自己的发展路径: 远期的理想是什么?近期的规划是什么?今日的任务和功课又是什么? 今日之任务或功课哪些有助于近期之规划的实现,而近期之规划是否有利于远期之理想? ...

  6. 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目 目录索引

    索引 [无私分享:从入门到精通ASP.NET MVC]从0开始,一起搭框架.做项目(1)搭建MVC环境 注册区域 [无私分享:从入门到精通ASP.NET MVC]从0开始,一起搭框架.做项目(2)创建 ...

  7. ASP.NET MVC4入门到精通系列目录汇总

    序言 最近公司在招.NET程序员,我发现好多来公司面试的.NET程序员居然都没有 ASP.NET MVC项目经验,其中包括一些工作4.5年了,甚至8年10年的,许多人给我的感觉是:工作了4.5年,We ...

  8. Web jquery表格组件 JQGrid 的使用 - 从入门到精通 开篇及索引

    因为内容比较多,所以每篇讲解一些内容,最后会放出全部代码,可以参考.操作中总会遇到各式各样的问题,个人对部分问题的研究在最后一篇 问题研究 里.欢迎大家探讨学习. 代码都经过个人测试,但仍可能有各种未 ...

  9. 1、ASP.NET MVC入门到精通——新语法

    本系列目录:ASP.NET MVC4入门到精通系列目录汇总 在学习ASP.NET MVC之前,有必要先了解一下C#3.0所带来的新的语法特性,这一点尤为重要,因为在MVC项目中我们利用C#3.0的新特 ...

随机推荐

  1. SpringBoot——报错总结

    前言 记录SpringBoot的相关报错信息 错误 无法引入@ResponseBody和@RequestMapping("/") <dependency> <gr ...

  2. wordpress数字分页列表导航实现

    前面我们用了自定义的方式来实现wordpress数字分页,其实wordpress是已经有集成了Numbered Pagination相关的函数,我们直接调用就可以.具体实现方法如下代码调用 <? ...

  3. Go语言 - goroutine

    并发与并行 并发:同一时间段内执行多个任务(你在用微信和两个女朋友聊天). 并行:同一时刻执行多个任务(你和你朋友都在用微信和女朋友聊天). Go语言的并发通过goroutine实现.goroutin ...

  4. str2int HDU - 4436 (后缀自动机)

    str2int \[ Time Limit: 3000 ms\quad Memory Limit: 131072 kB \] 题意 给出 \(n\) 个串,求出这 \(n\) 个串所有子串代表的数字的 ...

  5. MongoDB 几种查询嵌套数据(Embedded)的方式(转载)

    前言 MongoDB 推荐使用「内嵌文档(Embedded)」,所以带来一个问题,如何查询嵌入文档内的数据? 假如我们有一个 storage 的 Collection,包含一条数据: // `stor ...

  6. Xamarin.Forms之主题

    Xamarin.Forms应用程序可以使用DynamicResource标记扩展在运行时动态响应样式更改. 此标记扩展类似于StaticResource标记扩展,两者都使用字典键从ResourceDi ...

  7. SDU暑假排位第一场 (Gym - 100889)

    啊今天有点挂机啊 D题和队友暴力后发现一组数据跑得飞快 然后遇上1e5组数据就没了..... 然后我疯狂优化暴力 然后去世了 最后半小时F也没写出来 主要还是最后有点慌并且没有考虑清楚 导致情况越写越 ...

  8. 洛谷 P1396

    P1396 传送门 扯些题外话 讲真的我刚看到这个题的时候真的傻fufu的..... 大体题意 找出从s走到t的拥挤度最大值最小.. 思路 说最大值最小可能就会有dalao开始二分了. 想我这种的蒟蒻 ...

  9. SQL进阶-索引设置&sql优化

    一.索引设置 1.索引的设置原则 经常出现在WHERE条件.关联条件中的字段作为索引字段: 在满足查询需求的前提下,应尽可能少的创建索引:(对于一个组合索引,可以满足以组合索引左边的一部分字段的查询需 ...

  10. 洛谷P1979华容道

    题目 此题目中存在三种棋盘的放置方法(空白,不能活动,能活动). 而每次变化的格子一定在当前空白格子的周围,因此只需要对空白格子的周围四个状态考虑即可,因此我们设\(a[i][j][k]\)为白格子在 ...