java进阶教程-RabbitMQ入门指南

MQ 简介

消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。对于消息中间件,常见角色大致也就有 Producer(生产者)、Consumer(消费者)。
常见的消息中间件产品:
1). ActiveMQ
ActiveMQ 是 Apache 出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持 JMS1.1 和 J2EE 1.4 规范的 JMS Provider 实现。我们在本次课程中介绍 ActiveMQ 的使用。
2). RabbitMQ
AMQP 协议的领导实现,支持多种场景。淘宝的 MySQL 集群内部有使用它进行通讯,OpenStack 开源云平台的通信组件,最先在金融行业得到运用。
3). ZeroMQ
史上最快的消息队列系统
4). Kafka
Apache 下的一个子项目 。特点:高吞吐,在一台普通的服务器上既可以达到 10W/s的吞吐速率;完全的分布式系统。适合处理海量数据,

MQ 作用

1). 解耦 :中间件中的生产者只管发送消息 , 消费者只要从队列当中获取消息进行消费就可以 , 从而来实现业务的解耦

2). 冗余存储 : 有些情况下,处理数据的过程会失败。消息中间件可以把数据进行持久化直 到它们已经被完全处理,通过这一方式规避了数据丢失风险。在把一个消息从消息中间件中删 除之前,需要你的处理系统明确地指出该消息己经被处理完成,从而确保你的数据被安全地保 存直到你使用完毕。
3).可恢复性: 当系统一部分组件失效时,不会影响到整个系统 。 消息中间件降低了进程间的 稿合度,所以即使一个处理消息的进程挂掉,加入消息中间件中的消息仍然可以在系统恢复后 进行处理 。
4). 顺序保证: 在大多数使用场景下,数据处理的顺序很重要,大部分消息中间件支持一定程 度上的顺序性。
5). 缓冲: 在任何重要的系统中,都会存在需要不同处理时间的元素。消息中间件通过一个缓 冲层来帮助任务最高效率地执行,写入消息中间件的处理会尽可能快速 。
6). 异步通信: 在很多时候应用不想也不需要立即处理消息 。 消息中间件提供了异步处理机制,允许应用把一些消息放入消息中间件中,但并不立即处理它,在之后需要的时候再慢慢处理 。

RabbitMQ 安装及启动

1 安装依赖环境

rpm -ivh erlang-20.3.8.6-1.el6.x86_64.rpm
yum -y install epel-release
yum -y install socat

2 安装 rabbitMQ

rpm -ivh rabbitmq-server-3.7.7-1.el6.noarch.rpm

3 添加用户

默认情况下管理界面只能在 Linux 系统本机可以访问, 如果想其他的主机也能访问,需要
配置:
rabbitmq-plugins enable rabbitmq_management
添加访问用户:
rabbitmqctl add_user admin admin

4 RabbitMQ 启动/停止

启动 : service rabbitmq-server start
停止: service rabbitmq-server stop
查看状态: service rabbitmq-server status

Rabbit MQ 管理界面访问

1 Overview 概要

该栏目主要展示的是 MQ 的概要信息 , 如消息的数量, Connection , Channel,Exchange , Queue , Consumer 的数量.

2 Exchange 交换器

该栏目主要展示的是当前虚拟主机下的交换器,也可以在此添加一个新的交换器, 并且配置对应的交换器的规则属性 。

3 Queues 队列

该栏目展示的是消息队列的信息,里面有各个队列的概要信息, 也可以在此栏目添加队列Queue

4 Admin 系统管理

该栏目展示的是用户管理的信息, 包含用户列表的展示,添加用户,添加虚拟主机等信息

RabbitMQ 的相关概念

1 生产者与消费者

生产者

Producer: 生产者,就是投递消息的一方。
生产者创建消息,然后发布到 RabbitMQ 中。消息一般可以包含 2 个部分:消息体和标签 (Label)。消息体也可以称之为 payload ,在实际应用中,消 息体一般是一个带有业务逻辑结构 的数据,比如一个 JSON 字符串。当然可以进一步对这个消息体进行序列化操作。消息的标签用来表述这条消息 , 比如 一个交换器的名称和一个路由键 。 生产者把消息交由 RabbitMQ , RabbitMQ 之后会根据标签把消息发送给感兴趣的消费者(Consumer ) 。

消费者

Consumer: 消费者 ,就是接收消息的一方。
消费者连接到 RabbitMQ 服务器,并订阅到队列上 。当消费者消费一 条消息时 ,只是消费消息的消息体(payload )。在消息路由的过程中 ,消息的标签会丢弃 ,存入到队列中的消息只有消息体,消费者也只会消费到消息体 ,也就不知道消息的生产者是谁,当然消费者也不需要知道 。

.2 队列

Queue: 队列,是 RabbitMQ 的内部对象,用 于存储消息。

3 交换器, 路由键, 绑定

交换器

Exchange: 交换器。在上图中我们暂时可以理解成生产者将消息投递到队列中,实际上 这个在 RabbitMQ 中不会发生。真实情况是,生产者将消息发送到 Exchange (交换器),由交换器将消息路由到一个或者多个队列中。如果路由不到,或 许会返回给生产者,或许直接丢弃。这里可以将 RabbitMQ 中的交换器看作一个简单的实体。


RabbitMQ 中的 交换器有四种类型,四种类型分别是 fanout、direct、topic 、headers,不同的类型有着不 同的路由策略。

路由键

RoutingKey : 路由键 。
生产者将消息发给交换器 的时候, 一般会指定 一个 RoutingKey ,用 来指定这个消息的路由规则,而这个 RoutingKey 需要与交换器类型和绑定键 (BindingKey) 联合使用才能最终生效。在交换器类型和绑定键 (BindingKey) 固定的情况下,生产者可以在发送消息给交换器时, 通过指定 RoutingKey 来决定消息流向哪里。

绑定
Binding: 绑定。RabbitMQ 中通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键(BindingKey) ,这样 RabbitMQ 就知道如何正确地将消息路由到队列了。

4 交换器类型

1).fanout : 它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。
2).direct: 该 类 型 的 交 换 器 路 由 规 则 也 很 简 单 , 它 会 把 消 息 路 由 到 那 些BindingKey 和 RoutingKey 完全匹配的队列中。
3).topic : 前面讲到 direct 类型的交换器路由规则是完全匹配 BindingKey 和 RoutingKey ,但是这种严格的匹配方式在很多情况下不能满足实际业务的需求。topic 类型的交换器在匹配规则上进行了扩展,它与 direct 类型的交换器相似,也是将消息路由到 BindingKey 和 RoutingKey 相匹配的队 列中,但这里的匹配规则有些不同,它约定:RoutingKey 为一个点号"." 分割的字符串 , 如 : com.itcast.client ,com.itheima.exam。BindingKey 与 RoutingKey 一样也是点号"." 分割的字符串。BindingKey 中可以存在两种特殊的字符串 "*" 和 "#" , 用于模糊匹配,其中"#"用于匹配一个单词, "*"用于匹配多个单个(可以是零个)。
4). headers : 该类型的交换器不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中 的 headers 属性进行匹配。

生产者发送消息

1 队列绑定

创建队列

在 RabbitMQ 的后台管理界面中创建一个队列 , 指定队列名称。

创建交换器 Exchange

在 RabbitMQ 的后台管理界面中创建一个交换器,指定交换器的名称, 并且指定交换器类型。

绑定队列与交换器

在交换器列表点击对应的交换器,进入到绑定界面,指定队列名称queue,指 定 RoutingKey,通过该RoutingKey来绑定该队列与交换器 Exchange 。

之后,在发送消息时, 指定了 Exchange ,及 RoutingKey, 就可以将该消息路由 到该队列 queue 中。

2 发送消息逻辑代码

引入依赖

<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.2.0</version>
</dependency>

发送消息

@Test
public void test1() throws Exception{
//指定往哪一个交换器中发送消息
String exchangeName = "itcast.v0.topic";
//指定消息的路由RoutingKey
String routingKey = "itcast.item.add";
//创建一个连接工厂 , 指定 主机,端口, 访问的虚拟主机, 用户名, 密码
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.142.132");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
//创建一个链接
Connection connection = connectionFactory.newConnection();
//创建一个通道Channel
Channel channel = connection.createChannel();
//调用basicPublish循环发送50条消息 , 每条消息之间,间隔1秒
for (int i = 0; i < 50; i++) {
channel.basicPublish(exchangeName , routingKey ,
MessageProperties.TEXT_PLAIN , ("生产者生产的消息
083100"+i).getBytes());
TimeUnit.SECONDS.sleep(1);
}
}

发送消息平台监测

消费者接受消息

1 引入依赖

<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.2.0</version>
</dependency>

2 接收消息

@Test
public void test1() throws Exception{
//指定队列名称
String queueName = "itcast_item_add_queue";
//获取连接工厂 , 指定主机 , 端口, 虚拟主机 , 用户名 , 密码
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.142.132");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
//创建连接
Connection connection = connectionFactory.newConnection();
//创建通道Channel
Channel channel = connection.createChannel();
//设置客户端最多接收未被ack的消息的个数
channel.basicQos(10);
//构造消息者, 进行消息的消费
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
System.out.println("consumerTag : " + consumerTag);
System.out.println("properties : " +
JSON.toJSONString(properties));
System.out.println("envelope : " + JSON.toJSONString(envelope));
System.out.println("receive Message : " + new String(body) );
System.out.println("----------------------------------------");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//通过消息已经接受到
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(queueName, consumer);
System.in.read();//让程序等待在这里, 一直监听该消息队列
channel.close();
connection.close();
}

3 结果输出

其中:
consumerTag : 消息消费者的标签
properties : 消息内容的头信息数据
envelope : 消息体的数据包,其中包含消息发送时指定的exchange, routingKey等信息.

更多教程点击关注,私信可免费领取视频教程以及文档笔记

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章