routing
在之前的导航中,我们创建了一个简单日志系统,我们能够将日志信息广播到很多接受者。
在本篇导航中,我们将为其添加一个特性-我们将使订阅消息的一个子集成为可能。例如,我们能够将错误信息定向写入错误日志文件,同时能够在控制台打印所有信息。
binding
在之前的例子中我们能够创建绑定,你可能会回想起这样的代码
channel.queueBind(queueName, EXCHANGE_NAME, "");
绑定是交换和队列之间的关系。这可以简单地理解:队列对来自这个交换的消息感兴趣。
绑定可以使用额外的routingKey参数。为了避免与基本的发布参数混淆,我们将其称为绑定键。这就是我们如何键创建绑定的方法。
channel.queueBind(queueName, EXCHANGE_NAME, "black");
绑定键的意义取决于交换类型。我们之前使用的fanout交换机完全忽略了它的价值。
Direct exchange
我们之前使用的fanoutexchange,这并没有给我们多大的灵活性——它只能进行不需要动脑筋的广播。我们将用directexchange.消息可以传递到其绑定键bindingKey与消息的路由键routingkey完全匹配的队列
我们可以看到,这里面error可以发送到amqp.gen-S9b...和amqp.gen-Ag1...队列中,而info和waring只能发送到amqp.gen-Ag1...队列中
Send.java
public class Send {
private static final String EXCHANGE_NAME = "test_exchange_direct";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建channle
Channel channel = connection.createChannel();
// 声明exchange
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
String msg = "hello exchange direct";
String routingKey = "error";
channel.basicPublish(EXCHANGE_NAME, routingKey, null, msg.getBytes());
channel.close();
connection.close();
}
}
Rece1.java
public class Rece1 {
private static final String EXCHANGE_NAME = "test_exchange_direct";
private static final String QUEUE_NAME = "test_queue_direct1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"error");
channel.basicQos(1);
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body,"utf-8");
System.out.println("rece1 recieve msg :" + msg);
try{
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("rece1 done");
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
channel.basicConsume(QUEUE_NAME,false,consumer);
}
}
Rece2.java
public class Rece1 {
private static final String EXCHANGE_NAME = "test_exchange_direct";
private static final String QUEUE_NAME = "test_queue_direct1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"error");
channel.basicQos(1);
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body,"utf-8");
System.out.println("rece1 recieve msg :" + msg);
try{
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("rece1 done");
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
channel.basicConsume(QUEUE_NAME,false,consumer);
}
}
偶尔报错
队列绑定交换机时,routingKey是具有缓存机制的。我在写代码的时候,误操作了将队列都绑定了error,info,warning.我发现无法实现上述的效果,改了代码,但是还是无法解决。最后登录了RabbitMQ查看相关绑定。并使用的unbind功能。