(内容均来自RabbitMQ官网:https://www.rabbitmq.com/tutorials/tutorial-four-java.html)
前面几篇学习了下RabbitMQ的"HelloWorld","WorkQueue","Publish/Subscribe",也大概的了解了RabbitMQ几个基本的组件:连接、通道、路由器、队列、生产者、消费者。这一篇学习下Direct中的Routing模式。
上一篇中我们使用的交换机的类型是fanout类型,RabbitMQ官方介绍的是fanout类型没有很大的灵活性,它只是一种无意识的广播。所有,我们在多个消费者的情况下,多个消费者收到的信息不管是数量、内容上都是形同的。
其实Direct模式和Publish/Subscribe没啥大的出入,不同点就是两点
- 指定交换机类型为:Direct(Publish/Subscribe模式中的路由器类型为fanout,fanout模式下的路由器即使你填写了routingkey也会被系统忽略掉)
- 发送信息时候指定routingKey,就只指定要发送到哪个队列中
图例
RabbitMQ官网的栗子说的是log日志的栗子。如果现实开发中有这么一个需求,系统中产生的error类型的日志我们需要落盘,info、error、warning等类型的需要输出到控制台
生产者
这里在指定交换机类型为:direct,发送消息的时候用routingKey来区分我们需要路由器帮我们把消息投递到哪个队列。我们这里为了模拟error类型的消息和info类型的消息就简单的用i%3来区分
import com.booyue.tlh.utils.RabbitMQUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
public class Producer {
public static final String EXCHANGE_NAME = "logs_direct";
public static final String LOGS_ERROR = "logs.error";
public static final String LOGS_INFO = "logs.infor";
public static final String MESSAGE = " Dicrect_Routing类型的消息";
public static void main(String[] args) throws IOException {
//获取一个连接
Connection connection = RabbitMQUtils.getConnection();
//获取一个通道
Channel channel = connection.createChannel();
/**
* 声明一个交换机(运行完这一步,rabbitmq系统中就会创建一个名字和类型对应的)
* 参数1:交换机名称
* 参数2:交换机类型
*/
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
/**
* 往“logs_direct”交换机里发送20条"{i} Hello RabbitMQ"的信息。指定routingKey
*/
for (int i = 0; i < 10; i++) {
if (i % 3 == 0) {
//发送routingKey为logs.error的信息
channel.basicPublish(EXCHANGE_NAME, LOGS_ERROR, null, (i + MESSAGE).getBytes());
} else {
//发送routingKey为logs.infor的信息
channel.basicPublish(EXCHANGE_NAME, LOGS_INFO, null, (i + MESSAGE).getBytes());
}
}
}
}
消费者01和消费者02
这为了方便我就贴出了消费者01的代码,他们两个唯一不同的就是监听的routingKey和处理信息的业务逻辑不一样。消费者01监听的routingKey为:logs.error,消费者02监听的routingKey为:logs.info
import com.booyue.tlh.utils.RabbitMQUtils;
import com.rabbitmq.client.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
@Slf4j
public class Consumer01 {
public static final String EXCHANGE_NAME = "logs_direct";
public static final String LOGS_ERROR = "logs.error";
public static void main(String[] args) throws IOException {
//获取连接
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
//声明一个交换机,名字为:logs_direct,类型为:direct
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
//创建一个临时队列(临时队列在客户端断开之后会自动删除,释放系统资源)
String queueName = channel.queueDeclare().getQueue();
//创建绑定关系
channel.queueBind(queueName, EXCHANGE_NAME, LOGS_ERROR);
/**
* 接收消息
* 参数1:队列名
* 参数2:是否自动确认
* 参数3:消息回调接口
*/
channel.basicConsume(queueName, true, new DefaultConsumer(channel) {
@SneakyThrows
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) {
String message = new String(body, "utf-8");
try {
//模拟完成业务逻辑的耗时
Thread.sleep(1000);
} finally {
log.info("消费者1收到的信息:{}", message);
}
}
});
}
}
启动生产者和两个消费者,查看两个消费者收到的消息
能看到我们根据不同的routingKey就能收到不用的信息。那么在现实场景中就能做不同的事情了
23:00:01.711 [pool-1-thread-6] INFO com.booyue.tlh.direct_routing.Consumer01 - 消费者1收到的信息:0 Dicrect_Routing类型的消息
23:00:02.712 [pool-1-thread-6] INFO com.booyue.tlh.direct_routing.Consumer01 - 消费者1收到的信息:3 Dicrect_Routing类型的消息
23:00:03.712 [pool-1-thread-6] INFO com.booyue.tlh.direct_routing.Consumer01 - 消费者1收到的信息:6 Dicrect_Routing类型的消息
23:00:04.713 [pool-1-thread-6] INFO com.booyue.tlh.direct_routing.Consumer01 - 消费者1收到的信息:9 Dicrect_Routing类型的消息
23:00:01.712 [pool-1-thread-7] INFO com.booyue.tlh.direct_routing.Consumer02 - 消费者2收到的信息:1 Dicrect_Routing类型的消息
23:00:02.713 [pool-1-thread-7] INFO com.booyue.tlh.direct_routing.Consumer02 - 消费者2收到的信息:2 Dicrect_Routing类型的消息
23:00:03.713 [pool-1-thread-7] INFO com.booyue.tlh.direct_routing.Consumer02 - 消费者2收到的信息:4 Dicrect_Routing类型的消息
23:00:04.714 [pool-1-thread-7] INFO com.booyue.tlh.direct_routing.Consumer02 - 消费者2收到的信息:5 Dicrect_Routing类型的消息
23:00:05.714 [pool-1-thread-7] INFO com.booyue.tlh.direct_routing.Consumer02 - 消费者2收到的信息:7 Dicrect_Routing类型的消息
23:00:06.715 [pool-1-thread-7] INFO com.booyue.tlh.direct_routing.Consumer02 - 消费者2收到的信息:8 Dicrect_Routing类型的消息
总结下
- Direct中的Routing模式和Publish/Subscribe模式的区别就是交换机的类型不一样。
- Direct中的Routing模式中的交换机类型为direct
- Publish/Subscribe模式中的交换机类型为fanout
- Direct中的Routing模式下,会根据routingKey的值将消息投递到不同的队列里面,从而实现消息的分类、筛选