一、Direct类型
1.图解概述
如图所示,该模式下生产者发送消息给broker中的交换机(一个broker中可以有多个exchange交换机,一个exchange可以绑定多个queue队列),交换机根据这条消息携带的routing-key(123)来分发到这个routing-key对应的队列(queue1),因为queue1这个队列绑定的routing-key也是123,那这时,监听queue1的consumer1这个消费者就拿到了‘“张三”’这条消息,也就是说消费者和routing-key是没有直接关系的,消费者只需要关心应该关注哪个队列。
2.代码实现
2.1 创建一个maven工程,引入如下依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.7.3</version>
</dependency>
2.2 编写消息生产者的代码
public class Send {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
//配置链接信息
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null; //定义连接
Channel channel = null; //定义通道
try {
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//创建一个队列 名为myqueueDirect
channel.queueDeclare("myqueueDirect", false, false, false, null);
//再创建一个交换机
//由于发送消息时必须确保交换机已经创建,这行代码的作用如果该交换机没有则创建,如果存在,则不创建
channel.exchangeDeclare("directExchange","direct",true);
//通过routing-key(routing-direct)与队列(myqueueDirect)和交换机(directExchange)进行绑定
channel.queueBind("myqueueDirect","directExchange","routing-direct");
String message = "direct模式测试消息";
//生产者发送消息到directExchange交换机,消息携带的routing-key是routing-direct
channel.basicPublish("directExchange","routing-direct",null,message.getBytes("utf-8"));
System.out.println("消息发送完毕");
}catch (Exception e){
}finally {
channel.close();
connection.close();
}
}
}
2.3 编写消费者代码
public class Consumer {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory();
//配置链接信息
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null; //定义连接
Channel channel = null; //定义通道
try {
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//创建队列 可以不用创建,这里的作用时如果没有该队列则创建,如果有则放弃创建
channel.queueDeclare("myqueueDirect", false, false, false, null);
//再创建一个交换机 可以不用创建,这里的作用时如果没有该交换机则创建,如果有则放弃创建
channel.exchangeDeclare("directExchange","direct",true);
//通过routing-key与队列和交换机进行绑定
channel.queueBind("myqueueDirect","directExchange","routing-direct");
/**
* 监听某个队列并获取队列中的数据
*/
channel.basicConsume("myqueueDirect",true,"",new DefaultConsumer(channel){
@Override
public void handleDelivery(java.lang.String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
java.lang.String message = new java.lang.String(body, "utf-8");
System.out.println("消费者的消息 " + message);
}
});
}catch (Exception e){
}finally {
}
}
}
运行查看:
二、Fanout类型
1.图解概述
刚才的direct模式交换机在绑定queue时是需要一个routing-key的,一个routing-key绑定一个队列,而fanout模式不要routing-key,直接将队列与交换机进行绑定,消费者还是只监听队列就可以。
2.代码实现
2.1 编写生产者代码
public class FanoutSend {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
//配置链接信息
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null; //定义连接
Channel channel = null; //定义通道
try {
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//fanout模式的发送消息
//发送消息前定义一下,确保交换机一定存在
channel.exchangeDeclare("fanoutExchange","fanout",true);
String message = "fanout模式测试消息";
//不需要绑定routing-key,第二个参数为空即可
channel.basicPublish("fanoutExchange","",null,message.getBytes("utf-8"));
System.out.println("消息发送完毕");
}catch (Exception e){
}finally {
if (channel != null){
channel.close();
connection.close();
}
}
}
}
由于fanout模式类似于一种广播模式,所以这次创建2个消费者来监听
2.2 编写消费者1的代码
public class Consumer {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory();
//配置链接信息
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null; //定义连接
Channel channel = null; //定义通道
try {
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//由于fanout是一种广播模式,所以这里不需要指定特定的对列名,创建一个随机的队列名
String queueName = channel.queueDeclare().getQueue();
//创建一个交换机
channel.exchangeDeclare("fanoutExchange","fanout",true);
//fanout模式的交换机不需要绑定routing-key
channel.queueBind(queueName,"fanoutExchange","");
//消费者监听队列
channel.basicConsume(queueName,true,"",new DefaultConsumer(channel){
@Override
public void handleDelivery(java.lang.String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
java.lang.String message = new java.lang.String(body, "utf-8");
System.out.println("fanout:消费者1接受的消息 " + message);
}
});
}catch (Exception e){
}finally {
}
}
}
2.3 编写消费者2的代码
public class Consumer2 {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory();
//配置链接信息
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null; //定义连接
Channel channel = null; //定义通道
try {
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//创建一个随机的队列名
String queueName = channel.queueDeclare().getQueue();
//创建一个交换机
channel.exchangeDeclare("fanoutExchange","fanout",true);
//fanout模式的交换机不需要绑定routing-key
channel.queueBind(queueName,"fanoutExchange","");
/**
* 监听某个队列并获取队列中的数据
*/
channel.basicConsume(queueName,true,"",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("fanout:消费者2接受的消息 " + message);
}
});
}catch (Exception e){
}finally {
}
}
}
注意:这里一定要先启动两个消费者,否则如果先启动生产者,那么消费者将无法消费到生产者发送的消息。
运行查看:
可见fanout模式在发送消息时不需要给消息绑定routing-key,只需要将消息发送到指定交换机即可,交换机会将该消息发送给所有绑定的队列中去。
三、Topic
1.图解概述
topic类型的交换机使用通配符来动态的将消息发送给相应的队列,
该模式在交换机和队列进行绑定时是需要执行routing-key的,其中 “*” 必须匹配一个单词,“#”匹配0个或多个单词。(1)如果消息携带的routing-key为aa,则该消息会发送到queue1和queue3中去,因为queue2绑定的routing-key为aa. *,也就是aa后面必须要有一个单词。(2)如果消息携带的routing-key为aa.123,则该消息会发送到queue2和queue3中去,因为queue1绑定的routing-key为aa,也就是只能匹配routing-key等于aa的。(3)如果消息携带的routing-key为aa.123.bb,则该消息会发送到queue3中去,因为queue1绑定的routing-key只能匹配routing-key等于aa的。queue2绑定的routing-key只能匹配一个单词,而aa.#可以匹配0个或多个单词。
2.代码实现
2.1 编写生产者代码(第一次测试routing-key为aa)
public class TopicSend {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
//配置链接信息
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null; //定义连接
Channel channel = null; //定义通道
try {
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//fanout模式的发送消息
//发送消息前最好定义一下,确保交换机一定存在
channel.exchangeDeclare("topicExchange","topic",true);
String message = "topic模式测试消息";
//需要绑定routing-key,只会向符合routing-key规则的队列中发送消息
channel.basicPublish("topicExchange","aa",null,message.getBytes("utf-8"));
System.out.println("消息发送完毕");
}catch (Exception e){
}finally {
if (channel != null){
channel.close();
connection.close();
}
}
}
}
2.2 编写routing-key匹配 “aa” 的队列的消费者代码
public class Consumer {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory();
//配置链接信息
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null; //定义连接
Channel channel = null; //定义通道
try {
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//创建队列
channel.queueDeclare("topicQueue",true,false,false,null);
//再创建一个交换机
channel.exchangeDeclare("topicExchange","topic",true);
//绑定routing-key将队列与交换机进行绑定
channel.queueBind("topicQueue","topicExchange","aa");
/**
* 监听某个队列并获取队列中的数据
*/
channel.basicConsume("topicQueue",true,"",new DefaultConsumer(channel){
@Override
public void handleDelivery(java.lang.String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
java.lang.String message = new java.lang.String(body, "utf-8");
System.out.println("topic:消费者1(aa)接受的消息 " + message);
}
});
}catch (Exception e){
}finally {
}
}
}
2.3 编写routing-key匹配 “aa.*” 的队列的消费者代码
public class Consumer2 {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory();
//配置链接信息
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null; //定义连接
Channel channel = null; //定义通道
try {
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//创建队列
channel.queueDeclare("topicQueue2",true,false,false,null);
//再创建一个交换机
channel.exchangeDeclare("topicExchange","topic",true);
//绑定routing-key将队列与交换机进行绑定
channel.queueBind("topicQueue2","topicExchange","aa.*");
/**
* 监听某个队列并获取队列中的数据
*/
channel.basicConsume("topicQueue2",true,"",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("topic:消费者2( aa.* )接受的消息 " + message);
}
});
}catch (Exception e){
}finally {
}
}
}
2.4 编写routing-key匹配 “aa.#” 的队列的消费者代码
public class Consumer3 {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory();
//配置链接信息
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = null; //定义连接
Channel channel = null; //定义通道
try {
connection = connectionFactory.newConnection();
channel = connection.createChannel();
//创建队列
channel.queueDeclare("topicQueue3",true,false,false,null);
//再创建一个交换机
channel.exchangeDeclare("topicExchange","topic",true);
//绑定routing-key将队列与交换机进行绑定
channel.queueBind("topicQueue3","topicExchange","aa.#");
/**
* 监听某个队列并获取队列中的数据
*/
channel.basicConsume("topicQueue3",true,"",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("topic:消费者3( aa.# )接受的消息 " + message);
}
});
}catch (Exception e){
}finally {
}
}
}
生产者发送消息,运行查看:
可以看到,只有topicQueue和topicQueue3这两个队列接受到了消息,因为aa匹配这两个队列的routing-key(aa和aa.#)。
将生产的的消息的routing-key改为aa.123
生产者发送消息,运行查看:
可以看到,只有topicQueue2和topicQueue3这两个队列接受到了消息,因为aa.123匹配这两个队列的routing-key(aa.*和aa.#)。
将生产的的消息的routing-key改为aa.123.bb
生产者发送消息,运行查看:
可以看到,只有topicQueue3这个队列接受到了消息,因为aa.123.bb匹配这队列的routing-key(aa.#)。