消息中间件——RabbitMQ(六)理解Exchange交换机核心概念!


前言
来了解RabbitMQ一个重要的概念:Exchange交换机
1. Exchange概念
- Exchange:接收消息,并根据路由键转发消息所绑定的队列。

蓝色框:客户端发送消息至交换机,通过路由键路由至指定的队列。
黄色框:交换机和队列通过路由键有一个绑定的关系。
绿色框:消费端通过监听队列来接收消息。
2. 交换机属性
Name:交换机名称
Type:交换机类型——direct、topic、fanout、headers、sharding(此篇不讲)
Durability:是否需要持久化,true为持久化
Auto Delete:当最后一个绑定到Exchange上的队列删除后,自动删除该Exchange
Internal:当前Exchange是否用于RabbitMQ内部使用,默认为false
Arguments:扩展参数,用于扩展AMQP协议自定制化使用
3. Direct Exchange(直连)
- 所有发送到Direct Exchange的消息被转发到RouteKey中指定的Queue
注意:Direct模式可以使用RabbitMQ自带的Exchange:default Exchange,所以不需要将Exchange进行任何绑定(binding)操作,消息传递时,RouteKey必须完全匹配才会被队列接收,否则该消息会被抛弃。

重点:routing key与队列queues 的key保持一致,即可以路由到对应的queue中。
3.1 代码演示
生产端:
/**
*
* @ClassName: Producer4DirectExchange
* @Description: 生产者
* @author Coder编程
* @date2019年7月19日 下午22:15:52
*
*/
public class Producer4DirectExchange {
public static void main(String[] args) throws Exception {
//1创建ConnectionFactory
Connection connection = ConnectionUtils.getConnection();
//2创建Channel
Channel channel = connection.createChannel();
//3 声明
String exchangeName = "test_direct_exchange";
String routingKey = "test.direct";
//4 发送
String msg = "Coder编程 Hello World RabbitMQ 4 Direct Exchange Message ... ";
channel.basicPublish(exchangeName, routingKey , null , msg.getBytes());
}
}
消费端:
/**
*
* @ClassName: Consumer4DirectExchange
* @Description: 消费者
* @author Coder编程
* @date2019年7月19日 下午22:18:52
*
*/
public class Consumer4DirectExchange {
public static void main(String[] args) throws Exception {
//创建ConnectionFactory
Connection connection = ConnectionUtils.getConnection();
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);
}
}
}
测试结果:

注意需要routingKey保持一致。可以自己尝试修改routingkey,是否能收到消息。
4. Topic Exchange
- 所有发送到Topic Exchange的消息被转发到所有管线RouteKey中指定Topic的Queue上
- Exchange将RouteKey和某Topic进行模糊匹配,此时队列需要绑定一个Topic
注意:可以使用通配符进行模糊匹配
符号 "#" 匹配一个或多个词
符号 "" 匹配不多不少一个词
例如:"log.#" 能够匹配到 "log.info.oa"
"log." 只会匹配到 "log.error"

在一堆消息中,每个不同的队列只关心自己需要的消息。
4.1 代码演示
生产端:
/**
*
* @ClassName: Producer4TopicExchange
* @Description: 生产者
* @author Coder编程
* @date2019年7月19日 下午22:32:41
*
*/
public class Producer4TopicExchange {
public static void main(String[] args) throws Exception {
//1创建ConnectionFactory
Connection connection = ConnectionUtils.getConnection();
//2创建Channel
Channel channel = connection.createChannel();
//3声明
String exchangeName = "test_topic_exchange";
String routingKey1 = "user.save";
String routingKey2 = "user.update";
String routingKey3 = "user.delete.abc";
//4发送
String msg = "Coder编程 Hello World RabbitMQ 4 Topic Exchange Message ...";
channel.basicPublish(exchangeName, routingKey1 , null , msg.getBytes());
channel.basicPublish(exchangeName, routingKey2 , null , msg.getBytes());
channel.basicPublish(exchangeName, routingKey3 , null , msg.getBytes());
channel.close();
connection.close();
}
}
消费端:
/**
*
* @ClassName: Consumer4TopicExchange
* @Description: 消费者
* @author Coder编程
* @date2019年7月19日 下午22:37:12
*
*/
public class Consumer4TopicExchange {
public static void main(String[] args) throws Exception {
//创建ConnectionFactory
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
// 声明
String exchangeName = "test_topic_exchange";
String exchangeType = "topic";
String queueName = "test_topic_queue";
//String routingKey = "user.*";
String routingKey = "user.*";
// 1 声明交换机
channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
// 2 声明队列
channel.queueDeclare(queueName, false, false, false, null);
// 3 建立交换机和队列的绑定关系:
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. Fanout Exchange
- 不处理路由键,只需要简单的将队里绑定到交换机上
- 发送到交换机的消息都会被转发到与该交换机绑定的所有队列上
- Fanout交换机转发消息是最快的

5.1 代码演示
生产端:
/**
*
* @ClassName: Producer4FanoutExchange
* @Description: 生产者
* @author Coder编程
* @date2019年7月19日 下午23:01:16
*
*/
public class Producer4FanoutExchange {
public static void main(String[] args) throws Exception {
//1创建ConnectionFactory
Connection connection = ConnectionUtils.getConnection();
//2 创建Channel
Channel channel = connection.createChannel();
//3 声明
String exchangeName = "test_fanout_exchange";
//4 发送
for(int i = 0; i < 10; i ++) {
String msg = "Coder 编程 Hello World RabbitMQ 4 FANOUT Exchange Message ...";
channel.basicPublish(exchangeName, "", null , msg.getBytes());
}
channel.close();
connection.close();
}
}
消费端:
/**
*
* @ClassName: Consumer4FanoutExchange
* @Description: 消费者
* @author Coder编程
* @date2019年7月19日 下午23:21:18
*
*/
public class Consumer4FanoutExchange {
public static void main(String[] args) throws Exception {
//创建ConnectionFactory
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
// 声明
String exchangeName = "test_fanout_exchange";
String exchangeType = "fanout";
String queueName = "test_fanout_queue";
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);
}
}
}
测试结果:

6. 其他
6.1 Bingding —— 绑定
- Exchange和Exchange、Queue之间的连接关系
- Bingding可以包含RoutingKey或者参数
6.2 Queue——消息队列
- 消息队列,实际存储消息数据
- Durability:是否持久化,Durable:是 ,Transient:否
- Auto delete:如选yes,代表当最后一个监听被移除之后,该Queue会自动被删除。
6.3 Message——消息
- 服务器与应用程序之间传送的数据
- 本质上就是一段数据,由Properties和Payload(Body)组成
- 常用属性:delivery mode、headers(自定义属性)
6.4 其他属性
content_type、content_encoding、priority
correlation_id、reply_to、expiration、message_id
timestamp、type、user_id、app_id、cluster_id
6.5 Virtual Host虚拟主机
- 虚拟地址,用于进行逻辑隔离,最上层的消息路由
- 一个Virtual Host里面可以有若干个Exchange和Queue
- 同一个Virtual Host里面不能有相同名称的Exchange或Queue
7. 总结
RabbitMQ的概念、安装与使用、管控台操作、结合RabbitMQ的特性、Exchange、Queue、Binding
、RoutingKey、Message进行核销API的讲解,通过本章的学习,希望大家对RabbitMQ有一个初步的认识。
文末
欢迎关注个人微信公众号:Coder编程
获取最新原创技术文章和免费学习资料,更有大量精品思维导图、面试资料、PMP备考资料等你来领,方便你随时随地学习技术知识!
新建了一个qq群:315211365,欢迎大家进群交流一起学习。谢谢了!也可以介绍给身边有需要的朋友。
文章收录至
Github: https://github.com/CoderMerlin/coder-programming
Gitee: https://gitee.com/573059382/coder-programming
欢迎关注并star~
参考文章:
《RabbitMQ消息中间件精讲》
推荐文章:
消息中间件——RabbitMQ(三)理解RabbitMQ核心概念和AMQP协议!
消息中间件——RabbitMQ(四)命令行与管控台的基本操作!
消息中间件——RabbitMQ(五)快速入门生产者与消费者,SpringBoot整合RabbitMQ!
消息中间件——RabbitMQ(六)理解Exchange交换机核心概念!的更多相关文章
- 理解maven的核心概念
原文出处:http://www.cnblogs.com/holbrook/archive/2012/12/24/2830519.html 好久没进行java方面的开发了,最近又完成了一个java相关的 ...
- Docker入门——理解Docker的核心概念
1 前言 相信不少人听过这么一句话: 人类的本质是复读机. 在软件开发领域也一样,我们总是想寻找更好地方式复制优秀的逻辑或系统.最核心的方法是抽取通用逻辑和组件,把差异化的东西接口化或配置化,达到复用 ...
- 轻松理解 Kubernetes 的核心概念
Kubernetes 迅速成为云环境中软件部署和管理的新标准. 与强大的功能相对应的是陡峭的学习曲线. 本文将提供 Kubernetes 的简化视图,从高处观察其中的重要组件,以及他们的关联. 硬件 ...
- Maven 专题(六):Maven核心概念详解(二)
5 仓库 5.1 分类 [1]本地仓库:为当前本机电脑上的所有 Maven 工程服务.[2]远程仓库: (1)私服:架设在当前局域网环境下,为当前局域网范围内的所有 Maven 工程服务 ...
- 消息中间件——RabbitMQ(七)高级特性全在这里!(上)
前言 前面我们介绍了RabbitMQ的安装.各大消息中间件的对比.AMQP核心概念.管控台的使用.快速入门RabbitMQ.本章将介绍RabbitMQ的高级特性.分两篇(上/下)进行介绍. 消息如何保 ...
- 消息中间件——RabbitMQ(八)高级特性全在这里!(下)
前言 上一篇消息中间件--RabbitMQ(七)高级特性全在这里!(上)中我们介绍了消息如何保障100%的投递成功?,幂等性概念详解,在海量订单产生的业务高峰期,如何避免消息的重复消费的问题?,Con ...
- 消息中间件——RabbitMQ(九)RabbitMQ整合Spring AMQP实战!(全)
前言 1. AMQP 核心组件 RabbitAdmin SpringAMQP声明 RabbitTemplate SimpleMessageListenerContainer MessageListen ...
- webpack的四个核心概念介绍
前言 webpack 是一个当下最流行的前端资源的模块打包器.当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后 ...
- 通过核心概念了解webpack工作机制
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler).当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency gr ...
随机推荐
- ps aux | grep "svnserve" | cut -c 9-15 | xargs kill -9
ps aux | grep "svnserve" | cut -c 9-15 | xargs kill -9
- 【并查集】模板 + 【HDU 1213、HDU 1232、POJ 2236、POJ 1703】例题详解
不想看模板,想直接看题目的请戳下面目录: 目录: HDU 1213 How Many Tables[传送门] HDU 1232 畅通工程 [传送门] POJ 2236 Wireless Network ...
- Elasticsearch 技术分析(九):Elasticsearch的使用和原理总结
前言 之前已经分享过Elasticsearch的使用和原理的知识,由于近期在公司内部做了一次内部分享,所以本篇主要是基于之前的博文的一个总结,希望通过这篇文章能让读者大致了解Elasticsearch ...
- micropython TPYBoard v201 简易的web服务器的实现过程
转载请注明文章来源,更多教程可自助参考docs.tpyboard.com,QQ技术交流群:157816561,公众号:MicroPython玩家汇 前言 TPYBoard v201开发板上搭载了以太网 ...
- C#3.0新增功能09 LINQ 标准查询运算符 03 按执行方式的分类
连载目录 [已更新最新开发文章,点击查看详细] 标准查询运算符方法的 LINQ to Objects 实现主要通过两种方法之一执行:立即执行和延迟执行.使用延迟执行的查询运算符可以进一步分为两种 ...
- 一文了解有趣的位运算(&、|、^、~、>>、<<)
1.位运算概述 从现代计算机中所有的数据二进制的形式存储在设备中.即0.1两种状态,计算机对二进制数据进行的运算(+.-.*./)都是叫位运算,即将符号位共同参与运算的运算. 口说无凭,举一个简单的例 ...
- SQLyog12最新版破解
1.SQLyog-12.2.4-0.x64Trial.exe,直接去官网下载. 2.修改注册表项 开始-运行-regedit ,进入注册表 HKEY_CURRENT_USER\Software\ ...
- python课堂整理7---集合
前面小节: sep 用来控制每个元素间的间隔符号 print("alex", "dabai", "liu", sep = "&qu ...
- mysql 不同版本下 group by 组内排序的差异
最近发现网上找的 group by 组内排序语句在不同的mysql版本中结果不一样. 建表语句: SET FOREIGN_KEY_CHECKS=0; -- ---------------- ...
- Java后台处理框架之struts2学习总结
Java后台处理框架之struts2学习总结 最近我在网上了解到,在实际的开发项目中struts2的使用率在不断降低,取而代之的是springMVC.可能有很多的朋友看到这里就会说,那还不如不学str ...
