本文根据视频https://www.bilibili.com/video/BV1pa4y1x7Kc?p=9和https://www.bilibili.com/video/BV1pa4y1x7Kc?p=10创作。未经视频作者授权,如果作者感到侵权,请联系本人删除此文
路由模式结构图如下:
路由模式特点如下:
1. 一个交换机绑定多个队列,每个队列设置routingkey,一个队列可以设置多个routingkey
2. 每个消费者监听自己的队列
3. 生产者将消息发送给交换机,需要指定routingkey的值,交换机再转发给相同routingkey的队列
路由模式生产者代码:
public class RoutingProducer {
private static final String QUEUE_EMAIL = "queue_email";
private static final String QUEUE_SMS = "queue_sms";
private static final String EXCHANGE_ROUTING = "exchange_rounting";
private static final String EMAIL_ROUTING_KEY = "email_key";
private static final String SMS_ROUTING_KEY = "sms_key";
private static final String ALL_ROUTING_KEY = "all_key";
public static void main(String[] args) {
//通过连接工厂创建新的连接和MQ建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
//设置虚拟机,一个MQ可以设置多个虚拟机,每个虚拟机相当于一个独立的MQ
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null;
Channel channel = null;
try {
//建立新的连接
connection = connectionFactory.newConnection();
//创建会话通道,生产者和MQ服务所有通信都在channel通道中完成
channel = connection.createChannel();
//声明队列,如果队列在MQ中不存在则创建
channel.queueDeclare(QUEUE_SMS, true, false, false,null);
channel.queueDeclare(QUEUE_EMAIL, true, false, false,null);
//声明交换机
//参数: String exchange, String type
/**
* 参数明细
* 1. exchange 交换机名称
* 2. 交换机类型
* fanout: 对应发布订阅模式
* direct: 对应路由模式
* topic: 对应通配符模式
* headers: 对应header转发模式
*/
channel.exchangeDeclare(EXCHANGE_ROUTING, BuiltinExchangeType.DIRECT);
//绑定交换机和队列
//参数: String queue, String exchange, String routingKey
/**
* 参数明细:
* 1. queue 队列名称
* 2. exchange 交换机名称
* 3. routingKey 路由key,作用是交换机会根据路由key的值转发到指定的队列,在发布订阅模式为空串
*/
channel.queueBind(QUEUE_EMAIL, EXCHANGE_ROUTING, EMAIL_ROUTING_KEY);
//绑定多个队列
channel.queueBind(QUEUE_EMAIL, EXCHANGE_ROUTING, ALL_ROUTING_KEY);
channel.queueBind(QUEUE_SMS, EXCHANGE_ROUTING, SMS_ROUTING_KEY);
//绑定多个队列
channel.queueBind(QUEUE_SMS, EXCHANGE_ROUTING, ALL_ROUTING_KEY);
//发送消息制定rounting key
String message = "Hello World email";
String message1 = "Hello World sms";
String message2 = "Hello World all";
channel.basicPublish(EXCHANGE_ROUTING, EMAIL_ROUTING_KEY, null, message.getBytes());
channel.basicPublish(EXCHANGE_ROUTING, SMS_ROUTING_KEY, null, message1.getBytes());
channel.basicPublish(EXCHANGE_ROUTING, ALL_ROUTING_KEY, null, message2.getBytes());
System.out.println("send to mq " + message);
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接
//先关闭通道,在关闭连接
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
消费者email代码:
public class RoutingConsumerEmail {
private static final String QUEUE_EMAIL = "queue_email";
private static final String EXCHANGE_ROUTING = "exchange_rounting";
private static final String EMAIL_ROUTING_KEY = "email_key";
public static void main(String[] args) throws IOException, TimeoutException {
//通过连接工厂创建新的连接和MQ建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
//设置虚拟机,一个MQ可以设置多个虚拟机,每个虚拟机相当于一个独立的MQ
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null;
Channel channel = null;
//建立新的连接
connection = connectionFactory.newConnection();
//创建会话通道,生产者和MQ服务所有通信都在channel通道中完成
channel = connection.createChannel();
//声明队列,如果队列在MQ中不存在则创建
channel.queueDeclare(QUEUE_EMAIL, true, false, false, null);
//声明交换机
channel.exchangeDeclare(EXCHANGE_ROUTING, BuiltinExchangeType.DIRECT);
//绑定交换机和队列
channel.queueBind(QUEUE_EMAIL, EXCHANGE_ROUTING, EMAIL_ROUTING_KEY);
//实现消费方法
DefaultConsumer defaultConsumer = 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("receive message: " + message);
}
};
//监听队列
channel.basicConsume(QUEUE_EMAIL, true, defaultConsumer);
}
}
消费者SMS代码:
public class RoutingConsumerSms {
private static final String QUEUE_SMS = "queue_sms";
private static final String EXCHANGE_ROUTING = "exchange_rounting";
private static final String SMS_ROUTING_KEY = "sms_key";
public static void main(String[] args) throws IOException, TimeoutException {
//通过连接工厂创建新的连接和MQ建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
//设置虚拟机,一个MQ可以设置多个虚拟机,每个虚拟机相当于一个独立的MQ
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null;
Channel channel = null;
//建立新的连接
connection = connectionFactory.newConnection();
//创建会话通道,生产者和MQ服务所有通信都在channel通道中完成
channel = connection.createChannel();
//声明队列,如果队列在MQ中不存在则创建
channel.queueDeclare(QUEUE_SMS, true, false, false, null);
//声明交换机
channel.exchangeDeclare(EXCHANGE_ROUTING, BuiltinExchangeType.DIRECT);
//绑定交换机和队列
channel.queueBind(QUEUE_SMS, EXCHANGE_ROUTING, SMS_ROUTING_KEY);
//实现消费方法
DefaultConsumer defaultConsumer = 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("receive message: " + message);
}
};
//监听队列
channel.basicConsume(QUEUE_SMS, true, defaultConsumer);
}
}
关于代码验证结果有个疑问:
消费者没有绑定ALL_KEY这个路由key,但是可以接收到这个路由key的消息。如果启动了https://blog.csdn.net/wqc8994/article/details/106893121中的发布订阅模式的消费者,则all_key的信息不被路由消费者接收,而是被订阅消费者接收。目前个人不知道为啥,待以后有更深了解解决。如有知道的大佬也请评论告知。