主题模式与路由模式相似,发送到 topic
交换机的路由键必须是一个单词列表,由点号分隔。php
例如:stock.usd.nyse
、nyse.vmw
、quick.orange.rabbit
。算法
路由键中能够有任意多个单词,最多 255 个字节。json
同时绑定键也必须使用相同的形式。composer
# composer.json { "require": { "php-amqplib/php-amqplib": ">=3.0" } } > composer.phar install
topic
交换机背后的路由算法相似于 direct
交换,使用特定路由键发送的消息将被传递到使用匹配绑定键绑定的全部队列。函数
绑定键有两个重要的特殊状况:ui
上图的绑定能够总结为:spa
路由键设置为 quick.orange.rabbit
的消息将发送给两个队列。code
lazy.orange.elephant
也会发送给两个队列。rabbitmq
quick.orange.fox
只会进入第一个队列。队列
lazy.brown.fox
只会进入第二个队列。
lazy.pink.rabbit
只会进入第二个队列一次,即便命中了两次绑定规则。
quick.brown.fox
不会进入任何队列。
orange
和 quick.orange.male.rabbit
不会进入任何队列,会被丢弃。
lazy.orange.male.rabbit
会进入第二个队列,命中了最后一个规则。
主题交换机功能强大,支持其余全部交换机的功能。
当队列与 \#(井号)绑定键绑定时将接收全部消息,和
fanout
交换机同样。当绑定中不使用特殊字符 *(星号)和 \#(井号)时,和
direct
交换机同样。
生产者链接到RabbitMQ,发送一条消息,而后退出。
# send.php <?php require_once __DIR__ . '/vendor/autoload.php'; use PhpAmqpLib\Connection\AMQPStreamConnection; use PhpAmqpLib\Message\AMQPMessage; // 建立链接 $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest'); // 建立通道 $channel = $connection->channel(); // 定义一个名为 topic_logs 的 topic 交换机 $channel->exchange_declare('topic_logs', 'topic', false, false, false); // 从参数中获取交换机的路由键 $routing_key = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'anonymous.info'; $data = implode(' ', array_slice($argv, 2)); if (empty($data)) { $data = "Hello World!"; } // $msg = new AMQPMessage($data); // 经过名为 topic_logs 的 topic 交换机发送消息到队列 (消息内容, 交换机, 路由键); $channel->basic_publish($msg, 'topic_logs', $routing_key); echo ' [x] Sent ', $routing_key, ':', $data, "\n"; $channel->close(); $connection->close();
消费者监听来自RabbitMQ的消息,一般须要一直保持运行状态以监听消息。
# receive.php <?php require_once __DIR__ . '/vendor/autoload.php'; use PhpAmqpLib\Connection\AMQPStreamConnection; // 建立链接 $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest'); // 建立通道 $channel = $connection->channel(); // 定义一个名为 topic_logs 的 topic 交换机 $channel->exchange_declare('topic_logs', 'topic', false, false, false); // 建立一个随机命名的新队列,第三个参数为关闭队列持久化,第四个参数为当声明它的链接关闭时队列会被自动删除 list($queue_name, ,) = $channel->queue_declare("", false, false, true, false); // 定义全部的绑定键 $binding_keys = array_slice($argv, 1); if (empty($binding_keys)) { file_put_contents('php://stderr', "Usage: $argv[0] [binding_key]\n"); exit(1); } // 将随机命名的队列绑定到 topic 交换机,生产者向交换机发送消息将被放到绑定的队列中 foreach ($binding_keys as $binding_key) { $channel->queue_bind($queue_name, 'topic_logs', $binding_key); } echo " [*] Waiting for logs. To exit press CTRL+C\n"; // 定义回调函数 $callback = function ($msg) { echo ' [x] ', $msg->delivery_info['routing_key'], ':', $msg->body, "\n"; }; // 第四个参数设为true开启自动消息确认,即投递消息后马上标记为删除 $channel->basic_consume($queue_name, '', false, true, false, false, $callback); while ($channel->is_open()) { $channel->wait(); } $channel->close(); $connection->close();
打开一个终端,运行消费者,接收全部消息:
php receive.php "#"
打开另外一个终端,运行消费者,接收 kern.*
的消息:
php receive.php "kern.*"
打开另外一个终端,运行消费者,接收 *.critical
的消息:
php receive.php "*.critical"
打开另外一个终端,运行消费者,接收 kern.*
和 *.critical
的消息:
php receive.php "kern.*" "*.critical"
打开另外一个终端,运行生产者,发送一条 kern.critical
消息:
php send.php "kern.critical" "A critical kernel error"
sudo rabbitmqctl list_exchanges
sudo rabbitmqctl list_bindings