路由
在本教程中,我们将为其添加一个功能 - 我们将可以仅订阅一部分消息。例如,我们将能够仅将关键的错误消息引导到日志文件(以节省磁盘空间),同时仍然能够在控制台上打印所有日志消息。
绑定
在以前的例子中,我们已经创建了绑定。你可能会记得如下代码:
channel.queueBind(queueName, EXCHANGE_NAME, "");
绑定是交换机和队列之间的关系。这可以简单地读为:队列对来自此交换机的消息感兴趣。
绑定占用额外的routingKey 参数。为了避免与basic_publish 参数混淆,我们将其称为 绑定键。这就是我们如何用一个键创建一个绑定:
channel.queueBind(queueName, EXCHANGE_NAME, "black");
绑定键的含义取决于交换类型。以前我们以前使用的广播交换机忽略了它的价值。
点对点交换(direct)
我们从上一个教程的日志记录系统向所有消费者广播所有消息。我们希望将其扩展为允许基于其严重性过滤消息。例如,我们可能需要一个将日志消息写入磁盘以仅接收关键错误的程序,而不会浪费警告或信息日志消息上的磁盘空间。
我们使用广播式的交换机,它没有给我们很大的灵活性 - 它只能无意识地广播。
我们将使用点对点交换机。点对点交换背后的路由算法很简单 - 消息传递到绑定密钥与消息的路由密钥完全匹配的队列 。
为了说明,请考虑以下设置:
在这个设置中,我们可以看到点对点交换X与两个绑定的队列。第一个队列与绑定键橙色绑定,第二个队列有两个绑定,一个绑定键为黑色,另一个绑定为绿色。
在这样的设置中,发布到具有路由密钥橙色的交换机的消息 将被路由到队列Q1。具有黑色 或绿色路由密钥的消息将转到Q2。所有其他消息将被丢弃。
多重绑定
使用相同的绑定键绑定多个队列是完全合法的。在我们的示例中,我们可以在X和Q1之间添加绑定键黑色。在这种情况下,点对点交换将表现得像广播,并将消息广播到所有匹配的队列。具有路由密钥黑色的消息将传送到 Q1和Q2。
发出日志
我们将使用此模型进行日志记录系统。而不是广播,我们将发送消息到点对点交换。我们将提供日志严重性作为路由密钥。这样,接收程序将能够选择它想要接收的严重性。我们首先关注发送日志。
一如以往,我们首先要建立交流:
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
我们准备发送消息:
channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
为了简化事情,我们假设“严重性”可以是“信息”,“警告”,“错误”之一。
订阅
接收消息将像上一个教程一样工作,除了一个例外 - 我们将为每个我们感兴趣的严重性创建一个新的绑定。
String queueName = channel.queueDeclare().getQueue(); for(String severity : argv){ channel.queueBind(queueName, EXCHANGE_NAME, severity); }
把它们放在一起
EmitLogDirect.java类的代码:
import com.rabbitmq.client.*; import java.io.IOException; public class EmitLogDirect { private static final String EXCHANGE_NAME = "direct_logs"; public static void main(String[] argv) throws java.io.IOException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, "direct"); String severity = getSeverity(argv); String message = getMessage(argv); channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes()); System.out.println(" [x] Sent '" + severity + "':'" + message + "'"); channel.close(); connection.close(); } //.. }
ReceiveLogsDirect.java的代码:
import com.rabbitmq.client.*; import java.io.IOException; public class ReceiveLogsDirect { private static final String EXCHANGE_NAME = "direct_logs"; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, "direct"); String queueName = channel.queueDeclare().getQueue(); if (argv.length < 1){ System.err.println("Usage: ReceiveLogsDirect [info] [warning] [error]"); System.exit(1); } for(String severity : argv){ channel.queueBind(queueName, EXCHANGE_NAME, severity); } System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); Consumer consumer = new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String message = new String(body, "UTF-8"); System.out.println(" [x] Received '" + envelope.getRoutingKey() + "':'" + message + "'"); } }; channel.basicConsume(queueName, true, consumer); } }
像往常一样编译(参见教程一编译和类路径建议)。为方便起见,我们将在运行示例时使用环境变量$ CP(Windows上的%CP%)作为类路径。
javac -cp $ CP ReceiveLogsDirect.java EmitLogDirect.java
如果您只想将“警告”和“错误”(而不是“信息”)保存到文件中,只需打开控制台并键入:
java -cp $CP ReceiveLogsDirect warning error > logs_from_rabbit.log
如果您想查看屏幕上的所有日志消息,请打开一个新终端,然后执行以下操作:
java -cp $CP ReceiveLogsDirect info warning error # => [*] Waiting for logs. To exit press CTRL+C
而且,例如,要发出错误日志消息,只需键入:
java -cp $CP EmitLogDirect error "Run. Run. Or it will explode." # => [x] Sent 'error':'Run. Run. Or it will explode.'