准备工作:composer 引入 php-amqplib

说明:本文说明基于 Java(主要说明原理),实现使用 php

RabbitMQ Java 客户端使用 com.rabbitmq.client 作为顶级包名,关键的 Class 和 Interface 有 Cahnnel、Connection、ConnectionFactory、Consumer 等。AMQP 协议层面的操作通过 Channel 接口实现。Connection 是用来开启 Channel(信道)的,可以注册事件处理器,也可以在应用结束时关闭连接。与 RabbitMQ 相关的开发工作,基本上也是围绕 Connection 和 Channel 这两个类展开的。本文详细内容有这几点:连接、交换器/队列的创建与绑定、发送消息、消费消息、消费消息的确认和关闭连接。

1、连接 RabbitMQ

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

  在创建之后, $channel 可以用来发送或者接收消息了。

  注意要点:

  Connection 可以用来创建多个 Channel 实例,但是 Channel 实例不能在线程间共享,应用程序应该为每一个线程开辟一个 Channel。某些情况下 Channel 的操作可以并发运行,但是在其他情况下会导致网络上出现错误的通信帧交错,同时也会影响发送方确认(publisher confirm)机制的运行,所以多线程间共享 Channel 实例是非线程安全的。

  

2、使用交换器和队列

  交换器和队列是 AMQP 中 high-level 层面的构建模块,应用程序需确保在使用它们的时候就已经存在了,在使用之前需要先声明(declare)它们。

  下例演示了如何声明一个交换器和队列:

channel.exchangeDeclare(exchangeName, "direct", true);
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, exchangeName, routingKey);

  上面创建了一个持久化的、非自动删除的、绑定类型为 direct 的交换器,同时也创建了一个非持久化的、排他的、自动删除的队列(此队列的名称由 RabbitMQ 自动生成)。这里的交换器和队列也都没有设置特殊的参数。

  上面的代码也展示了如何使用路由键将队列和交换器绑定起来。上面声明的队列具备如下特性:只对当前应用中同一个 Connection 层面可用,同一个 Connection 的不同 Channel 可共用,并且也会在应用连接断开时自动删除。

  如果要在应用中共享一个队列,可以做如下声明:

channel.exchangeDeclare(exchangeName, "direct", true)
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, exchangeName, routingKey);

  这里的队列被声明为持久化的、非排他的、非自动删除的,而且也被分配另一个确定的已知的名称(由客户端分配而非 RabbitMQ 自动生成)。

  

  注意:Channel 的 API 方法都是可以重载的,比如 exchangeDeclare、queueDeclare。根据参数不同,可以有不同的重载形式,根据自身的需要进行调用。

  生产者和消费者都可以声明一个交换器或者队列。如果禅师声明一个已经存在的交换器或者队列,只要声明的参数完全匹配现存的交换器或者队列,RabbitMQ 就可以什么都不做,并成功返回。如果声明的参数不匹配则抛出异常。

exchangeDelcare 方法详解

  exchangeDeclare 有多个重载方法,这些重载方法都是由下面这个方法中缺省的某些参数构成的。

Exchange.DeclareOk exchangeDeclare(String, exchange,
String type, boolean durable,
boolean autoDelete, boolean internal,
Map<String, Object> arguments) throws IOException;

  这个方法的返回值是 Exchange.DeclareOk,用来标识成功声明了一个交换器。

  各个参数详细说明如下所述。

  exchange:交换器的名称。

  type:交换器的类型,常见的如 fanout、direct、topic。

  durable:设置是否持久化。durable 设置为 true 表示持久化,反之是非持久化。持久化可以将交换器存盘,在服务器重启的时候不会丢失相关信息。

  autoDelete:设置是否自动删除。autoDelete 设置为 true 表示自动删除。自动删除的前提是至少有一个队列或者交换器与这个交换器绑定,之后所有与这个交换器绑定的队列或者交换器都与此解绑。注意不能错误地把这个参数理解为:“当与此交换器连接的客户端都断开时,RabbitMQ 会自动删除本交换器。”

  internal:设置是否是内置的。如果设置为 true,则表示是内置的交换器,客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式。

  arguments:其他一些结构化参数,比如 alternate-exchange。

  exchangeDeclare 的其他重载方法如下:

  (1)Exchange.DeclareOk exchangeDeclare(String exchange, String type) throws IOException;

  (2)Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable) throws IOException;

  (3)Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, Map<String, Object> arguments) throws IOException;

  与此对应的,将第二个参数 String type 换成 BuiltInExchangeType type 对应的几个重载方法:

  (1)Exchange.DeclareOk exchangeDeclare(String exchange, BuiltInExchangeType type) throws IOException;

  (2)Exchange.DeclareOk exchangeDeclare(String exchange, BuiltInExchangeType type, boolean durable) throws IOException;

  (3)Exchange.DeclareOk exchangeDeclare(String exchange, BuiltInExchangeType type, boolean durable, boolean autoDelete, Map<String, Object> arguments) throws IOException;

  (4)Exchange.DeclareOk exchangeDeclare(String exchange, BuiltInExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments) throws IOException;

  与 exchangeDeclare 师出同门的还有几个方法,比如 exchangeDeclareNoWait 方法,具体定义如下(当然也有 BuiltInExchangeType 版的):

  

void exchangeDeclareNoWait(
String exchange,
String type,
boolean durable,
boolean autoDelete,
boolean internal,
Map<String, Object> arguments) throws IOException;

  这个 exchangeDeclareNoWait 比 exchangeDeclare 多设置了一个 nowait 参数,这个 nowait 参数指的是 AMQP 中 Exchange.Declare 命令的参数,意思是不需要服务器返回,注意这个方法的返回值是 void,而普通的 exchangeDeclare 方法的返回值是 Exchange.DeclareOk,意思是在客户端声明了一个交换器之后,需要等待服务器的返回(服务器会返回 Exchange.DeclareOk 这个 AMQP 命令)。

  针对 “exchangeDeclareNoWait 不需要服务器任何返回值” 这一点,考虑这样一种情况,在声明完一个交换器之后(实际服务器还没完成交换器的创建),那么此时客户端紧接着使用这个交换器,必然会发生异常。如果没有特殊的缘由和应用场景,并不建议使用这个方法。

  这里还有一个师出同门的另一个方法 exchangeDeclarePassive,这个方法的定义如下:

  Exchange.DeclareOk exchangeDeclarePassive(String name) throws IOException;

  这个方法在实际应用过程中还是非常有用的的,它主要用来检测相应的交换器是否存在。如果存在则正常返回;如果不存在则抛出异常:404 channel exception,同时 Channel 也会被关闭。

  有声明创建交换器的方法,当然也有删除交换器的方法。相应的方法如下:

  (1)Exchange.DeclareOk exchangeDelete(String exchange) throws IOException;

  (2)void exchangeDeleteNoWait(String exchange, boolean ifUnused) throws IOException;

  (3)Exchange.DeclareOk exchangeDelete(String exchange, boolean isUnused) throws IOException;

  其中 exchange 表示交换器的名称,而 isUnused 用来设置是否在交换器没有被使用的情况下删除。如果 isUnused 设置为 true,则只有在此交换器没有被删除的情况下才会被删除。如果设置为 false,则无论如何这个交换器都要被删除。

queueDeclare 方法详解

  queueDeclare 相对于 exchangeDeclare 方法而言,重载方法只有两个:

  (1)Queue.DeclareOk queueDeclare() throws IOException;

  (2)Queue.DeclareOk queueDeclare(String queue, boolean, durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments) throws IOException;

  不带任何参数的 queueDeclare 方法默认创建一个由 RabbitMQ 命名的(类似这种 amq.gen-JAuqPPQWl3 名称,这种队列也称之为匿名队列)、排他的、自动删除的、非持久化的队列。

  方法的参数详细说明如下所述:

  queue:队列的名称。

  durable:设置是否持久化。为 true 则设置队列为持久化。持久化的队列会存盘,在服务器重启的时候可以保证不丢失相关信息。

  exclusive:设置是否排他。为 true 则设置队列为排他的。如果一个队列被声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除。这里需要注意三点:排他队列是基于连接(Connection)可见的,同一个连接的不同信道(Channel)是可以同时访问同一连接创建的排他队列:“首次”是指如果一个连接已经声明了一个排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同;即使该队列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除,这种队列适用于一个客户端同时发送和读取消息的应用场景。

  autoDelete:设置是否自动删除。为 true 则设置队列为自动删除。自动删除的前提是:至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,才会自动删除。不能把这个参数错误地理解为:“当连接到此队列的所有客户端断开时,这个队列自动删除”,因为生产者客户端创建这个队列,或者没有消费者客户端与这个队列连接时,都不会自动删除这个队列。

  arguments:设置队列的其他一些参数,如 x-message-ttl、x-expires、x-max-length、x-max-length-bytes、x-dead-letter-exchange、x-dead-letter-routing-key、x-max-priority 等。

  注意要点:

  生产者和消费者都能够使用 queueDeclare 来声明一个队列,但是如果消费者在同一个信道上订阅了另一个队列,就无法再声明队列了。必须先取消订阅,然后将信道置为 “传输” 模式,之后才能声明队列。

  对应于 exchangeDeclareNoWait 方法,这里也有一个 queueDeclareNoWait 方法:

  void queueDeclareNoWait(String queue, boolean durable, boolean exclusive,

    boolean autoDelete, Map<String, Object> arguments) throws IOException;

  方法的返回值也是 void,表示不需要服务端的任何返回。同样也需要注意,在调用完 queueDeclareNoWait 方法之后,紧接着使用声明的队列时有可能会发生异常情况。

  同样这里还有一个 queueDeclarePassive 的方法,也比较常用。这个方法用来检测相应的队列是否存在。如果存在则正常返回,如果不存在则抛出异常:404 channel exception,同时 Channel 也会被关闭。方法定义如下:

  Queue.DeclareOk queueDeclarePassive(String queue) throws IOException;

  与交换器对应,队列也有删除的相应方法:

  (1)Queue.DeleteOk queueDelete(String queue) throws IOException;

  (2)Queue.DeleteOk queueDelete(String queue, boolean ifUnused, boolean ifEmpty) throws IOException;

  (3)Queue.DeleteOk queueDelete(String queue, boolean ifUnused, boolean ifEmpty) throws IOException;

  其中 queue 表示队列的名称,ifUnused 可以参考上面的交换器。ifEmpty 设置为 true 表示在队列为空(队列里面没有任何消息堆积)的情况才能够删除。

  与队列相关的还有一个有意思的方法-queuePurge,区别于 queueDelete,这个方法用来清空队列中的内容,而不删除队列本身,具体定义如下:

  QueuePurgeOk queuePurge(String queue) throws IOException;

  

RabbitMQ 客户端开发向导的更多相关文章

  1. RabbitMQ:二、客户端开发向导

    建立Connection,创建Channel,注意Channel不能在线程间共享(非线程安全) 创建交换器和队列 消费者消费消息支持推和拉两种模式 推:通过consume方法订阅队列 拉:通过chan ...

  2. 几年前,为什么我撸了一套RabbitMQ客户端?

    之前文章说过,如果使用 RabbitMQ,尽可能使用框架,而不要去使用 RabbitMQ 提供的 Java 版客户端. 细说起来,其实还是因为 RabbitMQ 客户端的使用有很多的注意事项,稍微不注 ...

  3. C#.NET 大型通用信息化系统集成快速开发平台 4.0 版本 - 多系统开发接口 - 苹果客户端开发接口

    最近工作上需要,给苹果客户端开发接口,实现集中统一的用户管理,下面是接口调用参考. 1: 获取OpenId? http://127.0.0.1/GetOpenId.ashx?username=Admi ...

  4. 在线教学、视频会议 Webus Fox(3) 客户端开发手册

    本文主要介绍webus fox 客户端的配置及接口说明. 1. 文件列表和配置 1.1 文件列表 1.2 common.xml 配置 根据服务器端的部署, 替换[ServerUrl] , [RtmpP ...

  5. [原创]上海好买基金招高级Java技术经理/运维主管/高级无线客户端开发等职位(内推)

    [原创]上海好买基金招高级Java技术经理/运维主管/高级无线客户端开发等职位(内推) 内部推荐职位 高级JAVA技术经理: 岗位职责: 负责项目管理(技术方向),按照产品开发流 ,带领研发团队,制定 ...

  6. iOS客户端开发与Web前端开发

    转载自:http://blog.cnbang.net/tech/1813/不知不觉做iOS客户端开发已经半年多了,了解到iOS客户端开发与Web前端开发的一些异同,写一下. 版本升级.用户角度上看,客 ...

  7. 基于Android的小巫新闻客户端开发系列教程

    <ignore_js_op> 141224c6n6x7wmu1aacap7.jpg (27.51 KB, 下载次数: 0) 下载附件  保存到相册 23 秒前 上传   <ignor ...

  8. ASP.NET5之客户端开发:Grunt和Gulp构建工具在Visual Studio 2015中的高效的应用

    Grunt和Gulp是Javascript世界里的用来做自动压缩.Typescript编译.代码质量lint工具.css预处理器的构建工具,它帮助开发者处理客户端开发中的一些烦操重复性的工作.Grun ...

  9. 用Jersey为Android客户端开发Restful Web Service

    平时在做Android客户端的时候经常要与服务器之间通信,客户端通过服务端提供的接口获取数据,然后再展示在客户端的界面上,作为Android开发者,我们平时更多的是关注客户端的开发,而对服务端开发的关 ...

随机推荐

  1. 20155339 Exp7 网络欺诈防范

    20155339 Exp7 网络欺诈防范 .基础问题回答 (1)通常在什么场景下容易受到DNS spoof攻击 当连接局域网的时候应该最容易被攻击,比如说连接了一些不清楚是什么的WiFi其实是很容易收 ...

  2. 五、MYSQL的索引

    对于建立的索引(姓,名字,data) 5.1.索引对一下的查询类型有效 1.全值匹配:能查找姓+名为ALLEN.出生日期为1990-11-05的人: 2.最左前缀匹配:可以查找姓为ALLEN的人:即只 ...

  3. Luogu P1196 [NOI2002]银河英雄传说

    一年没写博客了(滑稽). 这道题很玄学,导致自己都有一个坑人的问题求解.如果有大佬有能力求帮助:https://www.luogu.org/discuss/show?postid=30231 再来讲一 ...

  4. Jmeter(二十二)_脚本上传Gitlab

    Docker部署接口自动化持续集成环境第四步,代码上传到远程仓库! 接上文:Ubuntu部署jmeter与ant Gitlab在容器中部署好了之后,本地直接打开.我们可以在里面创建项目,上传脚本. 新 ...

  5. Selenium和TestNG

    本文档由Felipe Knorr Kuhn撰写,并根据其博客上发布的一系列文章进行改编. 建模您的测试用例 在编写测试用例之前,您需要知道如何验证以及将要验证的内容.让我们使用WordPress “创 ...

  6. 日本厚劳省对IT技术人员展开确保海外人才调查

    新浪美股讯 5月13日消息,共同社报道,日本厚生劳动省将开始对在国内工作的外国籍系统工程师(SE)及程序员的劳动条件进行实际状况调查.为避免在与海外的人才获取竞争中败北,希望掌握接纳企业的需求等推动企 ...

  7. 《Linux内核分析》第三周

    [李行之原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] <Linux内 ...

  8. extjs几个奇怪的错误

    在用Extjs进行网页开发的时候,遇见了一下两个错误,这两个错误的位置用firebug调试显示在extjs-all.js Ext.resetElement is undefined g.el is n ...

  9. WAMP的一些配置修改

    一.修改php运行的目录,即www目录 1. 在工具栏里点击 Apache->httpd.conf 2. 找到 DocumentRoot "G:/PHP/wamp/www/" ...

  10. sql 索引 sql_safe_updates

    为了数据的安全性,mysql有一个安全性设置,sql_safe_updates ,当把这个值设置成1的时候,当程序要对数据进行修改删除操作的时候条件必须要走索引. 刚好现在也碰到了此类问题:网上找了相 ...