Exchange 用于接收消息,并根据路由键转发消息到所绑定的队列。
上图来源于某视频课程截图,如侵权,请联系立即删除!
从图中可以看出,Exchange 与 Queue 是通过 RoutingKye 来进行关联的,且 Exchange 与 Queue 是多对多的关系。
交换机常见属性
Name: 交换机名称
Type: 交换机类型,主要有 direct topic fanout headers
Durability: 是否需要持久化,true 表示持久化
Auto Delete: 当最后一个绑定到 Exchange上的队列删除后,自动删除该 Exchange
Internal: 当前 Exchange 是否用于 RabbitMQ 内部使用,默认为 False
Arguments: 扩展参数,用于扩展 AMQP 协议自定化使用
常用交换机类型
Direct Exchange
所有发送到 Direct Exchange 的消息被转发到 RouteKey 中指定的 Queue。此类型 Exchange 中生产者发送消息指定的 routingKey 与 消费者中 Exchange 和 Queue 绑定时指定的 routingKey 相同,否则发送失败。
注意:Direct 模式可以使用 RabbitMQ 自带的 Exchange(default Exchange),所以可以不需要将 Exchange 进行任何绑定操作,但是消息传递时,RouteKey 必须完全匹配才会被队列接收,否则该消息会被抛弃。
上图来源于某视频课程截图,如侵权,请联系立即删除!
DirectProducer.java
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class DirectProducer {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.125");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
// 获取连接
Connection connection = connectionFactory.newConnection();
// 创建信道
Channel channel = connection.createChannel();
// 通过信道发送信息
String exchangeName = "test.exchange.direct";
String routingKey = "key.direct";
for(int i = 0; i < 3; i++) {
String msg = "rabbitmq Producer: direct exchange test send message ";
// channel.basicPublish(exchange, routingKey, props, body);
channel.basicPublish(exchangeName, routingKey, null, msg.getBytes());
System.out.println("生产端消息已发送。。。");
}
// 关闭连接
channel.close();
connection.close();
}
}
DirectConsumer.java
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
public class DirectConsumer {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.125");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个队列
String queueName = "test.queue.direct";
// channel.queueDeclare(queue, durable, exclusive, autoDelete, arguments);
channel.queueDeclare(queueName, true, false, false, null);
// 声明一个交换机
String exchangeName = "test.exchange.direct";
String exchangeType = "direct";
String routingKey = "key.direct"; //与生产者发送消息使用的routingKey一样
// channel.exchangeDeclare(exchange, type, durable, autoDelete, internal, arguments);
channel.exchangeDeclare(exchangeName, exchangeType, false, false, false, null);
//交换机与队列绑定
channel.queueBind(queueName, exchangeName, routingKey);
// 创建消费者
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");
//TODO 自己的业务
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
//消息id
long deliveryTag = envelope.getDeliveryTag();
//消息内容
System.err.println("消费端收到 message : " + msg);
}
};
channel.basicConsume(queueName, true, consumer);
// channel.close();
// connection.close(); 流先不关闭,要不然看不到System.err.println的输出
}
}
由于本服务器还没有我定义的 Exchange ,因此先运行消息消费者程序,先声明相应的 Exchange 和 Queue 。
此时登录 RabbitMQ 管控台,可以查看本程序声明的 Exchange 和 Queue,及它们的绑定关系。
Direct 类型的 Exchange 中 routingKey 必须相同
这时运行生产者程序,发送消息到 RabbitMQ 服务器,再运行消息消费者程序即可接收消息。
Topic Exchange
所有发送到 Topic Exchange 的消息被转发到所有关心 RouteKey 中指定 Topic 的 Queue 上。通俗地说:Exchange 会将 RouteKey 和某 Topic 进行模糊匹配,此时队列需要绑定一个 Topic
注意:可以使用通配符进行模糊匹配
“ # ”——匹配一个或多个词
“ * ” ——匹配一个词
例如:" hello.# " 能匹配到"hello.world.test"
" hello.* " 只能匹配到"hello.world"
上图来源于某视频课程截图,如侵权,请联系立即删除!
Topic Exchange 消息的生产与消费与 Direct Exchange 类似,只是 Exchange 的类型换了,下面就只贴关键代码。
TopicProducer.java
// 通过信道发送信息
String exchangeName = "test.exchange.topic";
String routingKey1 = "key.topic.hello";
String routingKey2 = "key.topic.world";
String routingKey3 = "key.topic.test.hello";
String msg = "rabbitmq Producer: topic exchange test send message ";
// channel.basicPublish(exchange, routingKey, props, body);
// 用3个不同的 routingKey 各发送一条消息
channel.basicPublish(exchangeName, routingKey1, null, msg.getBytes());
channel.basicPublish(exchangeName, routingKey2, null, msg.getBytes());
channel.basicPublish(exchangeName, routingKey3, null, msg.getBytes());
System.out.println("生产端消息已发送,请查收。。。");
TopicConsumer.java
// 声明一个队列
String queueName = "test.queue.topic";
// channel.queueDeclare(queue, durable, exclusive, autoDelete, arguments);
channel.queueDeclare(queueName, true, false, false, null);
// 声明一个交换机
String exchangeName = "test.exchange.topic";
String exchangeType = "topic";
// String routingKey = "key.topic.#";
String routingKey = "key.topic.*";
// channel.exchangeDeclare(exchange, type, durable, autoDelete, internal, arguments);
channel.exchangeDeclare(exchangeName, exchangeType, false, false, false, null);
//交换机与队列绑定
channel.queueBind(queueName, exchangeName, routingKey);
如果Exchange 与 Queue 进行绑定时用的 RoutingKey 是 “ key.topic.* ”,消费端将只能收到2条消息。如果绑定时 RoutingKey 是“ key.topic.# ”,则消费端可以收到生产端发送的3条消息。
注意:在测试第二种绑定方式时,记得先去解绑前一种绑定方式
Fanout Exchange
不处理任何路由键,只需简单地把队列绑定到交换机上
发送到交换机的消息都会被转发到与该交换机绑定的所有队列上
Fanout 交换机转发消息是最快的,因为不用匹配 routingKey 。
上图来源于某视频课程截图,如侵权,请联系立即删除!
FanoutProducer.java
// 通过信道发送信息
String exchangeName = "test.exchange.fanout";
String msg = "rabbitmq Producer: fanout exchange test send message ";
// channel.basicPublish(exchange, routingKey, props, body);
channel.basicPublish(exchangeName, "", null, msg.getBytes());//这里的路由键可以任意,也可以没有
System.out.println("生产端消息已发送,请查收。。。");
FanoutConsumer.java
// 声明一个队列
String queueName = "test.queue.fanout";
// channel.queueDeclare(queue, durable, exclusive, autoDelete, arguments);
channel.queueDeclare(queueName, true, false, false, null);
// 声明一个交换机
String exchangeName = "test.exchange.fanout";
String exchangeType = "fanout";
String routingKey = "";//不设置路由键
// channel.exchangeDeclare(exchange, type, durable, autoDelete, internal, arguments);
channel.exchangeDeclare(exchangeName, exchangeType, false, false, false, null);
//交换机与队列绑定
channel.queueBind(queueName, exchangeName, routingKey);