交换机在使用前都需要绑定(bindings)队列,什么是 binding 呢,binding 其实是 exchange 和 queue 之间的桥梁,它告诉我们 exchange 和哪个队列进行了绑定关系。
绑定关系介绍:
一、Fanout(扇出交换机)
Fanout 这种类型非常简单。它将接收到的所有消息广播到它知道的所有队列中(RoutingKey一致的情况下)。通俗点说,使用了扇出(Fanout)类型的交换机可以将消息转发到所有它绑定的队列中,每一个队列都可接收到消息。
代码:
生产者:
package com.run.rabbitmq.five;
import com.rabbitmq.client.Channel;
import com.run.rabbitmq.utils.RabbitMqUtils;
import java.util.Scanner;
/**
* @Date: 2021/07/07/9:56
*
*
* 发消息 交换机
*/
public class EmitLog {
//交换机的名称
public static final String EXCHANGER_NAME = "logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
//声明交换机类型
channel.exchangeDeclare(EXCHANGER_NAME,"fanout");
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
String message = scanner.next();
channel.basicPublish(EXCHANGER_NAME,"",null,message.getBytes());
System.out.println("生产者发送消息:"+message);
}
}
}
消费者 1:
package com.run.rabbitmq.five;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.run.rabbitmq.utils.RabbitMqUtils;
/**
* @Date: 2021/07/07/9:45
*
* 消息接收
*/
public class ReceiveLogs01 {
//交换机名称
public static final String EXCHANGE_NAME = "logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
//声明一个交换机
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
//声明一个临时队列
/**
* 生成一个临时队列、队列的名称是随机的
* 当消费者断开与队列的连接的时候 队列就自动删除
*/
String queueName = channel.queueDeclare().getQueue();
/**
* 绑定交换机与队列
*/
channel.queueBind(queueName,EXCHANGE_NAME,"");
System.out.println("等待接收消息....把接受到的消息打印在终端");
//接收消息
DeliverCallback deliverCallback = (consumerTag,message) -> {
System.out.println("消费机01 接收消息:"+new String(message.getBody()));
};
//消费者取消消息回调接口
channel.basicConsume(queueName,true,deliverCallback,consumerTge ->{});
}
}
消费者 2:
package com.run.rabbitmq.five;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.run.rabbitmq.utils.RabbitMqUtils;
/**
* @Date: 2021/07/07/9:45
*
* 消息接收
*/
public class ReceiveLogs02 {
//交换机名称
public static final String EXCHANGE_NAME = "logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
//声明一个交换机
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
//声明一个临时队列
/**
* 生成一个临时队列、队列的名称是随机的
* 当消费者断开与队列的连接的时候 队列就自动删除
*/
String queueName = channel.queueDeclare().getQueue();
/**
* 绑定交换机与队列
*/
channel.queueBind(queueName,EXCHANGE_NAME,"");
System.out.println("等待接收消息....把接受到的消息打印在终端");
//接收消息
DeliverCallback deliverCallback = (consumerTag,message) -> {
System.out.println("消费机02 接收消息:"+new String(message.getBody()));
};
//消费者取消消息回调接口
channel.basicConsume(queueName,true,deliverCallback,consumerTge ->{});
}
}
二、Direct exchange(直接交换机)
direct 这种类型的工作方式是,消息只去到它绑定的routingKey 队列中去。
代码:
生产者:
package com.run.rabbitmq.six;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.run.rabbitmq.utils.RabbitMqUtils;
import java.util.Scanner;
/**
* @Date: 2021/07/07/10:29
*
* 直接交换机 生产者
*/
public class DirectLogs {
//交换机的名称
public static final String EXCHANGER_NAME = "direct_logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
channel.exchangeDeclare(EXCHANGER_NAME, BuiltinExchangeType.DIRECT);
Scanner scanner = new Scanner(System.in);
System.out.println("error info warning");
while (scanner.hasNext()){
String message = scanner.next();
channel.basicPublish(EXCHANGER_NAME,message,null,message.getBytes());
System.out.println("生产者发送消息:"+message);
}
}
}
消费者 1:
package com.run.rabbitmq.six;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.run.rabbitmq.utils.RabbitMqUtils;
/**
* @Date: 2021/07/07/10:20
*
* 直接交换机 消费者
*/
public class ReceiveLogsDirect01 {
public static final String EXCHANGE_NAME = "direct_logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
//声明一个交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//声明一个队列
channel.queueDeclare("console",false,false,false,null);
//队列绑定交换机
channel.queueBind("console",EXCHANGE_NAME,"info");
channel.queueBind("console",EXCHANGE_NAME,"warning");
//接收消息
DeliverCallback deliverCallback = (consumerTag, message) -> {
System.out.println("ReceiveLogsDirect01 接收消息:"+new String(message.getBody()));
};
channel.basicConsume("console",true,deliverCallback, consumerTag -> {});
System.out.println("等待接收消息....把接受到的消息打印在终端");
}
}
消费者 2 :
package com.run.rabbitmq.six;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.run.rabbitmq.utils.RabbitMqUtils;
/**
* @Date: 2021/07/07/10:20
*
* 直接交换机 生产者
*/
public class ReceiveLogsDirect02 {
public static final String EXCHANGE_NAME = "direct_logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
//声明一个交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//声明一个队列
channel.queueDeclare("disk",false,false,false,null);
//队列绑定交换机
channel.queueBind("disk",EXCHANGE_NAME,"error");
//接收消息
DeliverCallback deliverCallback = (consumerTag, message) -> {
System.out.println("ReceiveLogsDirect02 接收消息:"+new String(message.getBody()));
};
channel.basicConsume("disk",true,deliverCallback, consumerTag -> {});
System.out.println("等待接收消息....把接受到的消息打印在终端");
}
}
三、Topics交换机(主题交换机)
使用最广泛也是最强大的交换机。特点是可以发送到类型, topic 交换机的消息的 routing_key 不能随意写,必须满足一定的要求,它必须是一个单词列表,以点号分隔开。这些单词可以是任意单词,比如说:“stock.usd.nyse”, “nyse.vmw”, “quick.orange.rabbit”.这种类型的。当然这个单词列表最多不能超过 255 个字节。
在这个规则列表中,其中有两个替换符是大家需要注意的
*(星号)可以代替一个单词
#(井号)可以替代零个或多个单词
当队列绑定关系是下列这种情况时需要引起注意
当一个队列绑定键是#,那么这个队列将接收所有数据,就有点像 fanout 了
如果队列绑定键当中没有#和*出现,那么该队列绑定类型就是 direct 了
代码:
消费者 1 :
package com.run.rabbitmq.seven;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.run.rabbitmq.utils.RabbitMqUtils;
/**
* @Date: 2021/07/07/10:49
*
*
* 主题交换机 消费者 1
*/
public class ReceiveLogsTopic01 {
public static final String EXCHANGE_NAME = "topic_logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
//声明一个交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
//声明一个队列
String queueName = "Q1";
channel.queueDeclare(queueName,false,false,false,null);
//队列绑定交换机
channel.queueBind(queueName,EXCHANGE_NAME,"*.orange.*");
//接收消息
DeliverCallback deliverCallback = (consumerTag, message) -> {
System.out.println("ReceiveLogsTopic01 接收消息:"+new String(message.getBody()));
};
channel.basicConsume(queueName,true,deliverCallback, consumerTag -> {});
System.out.println("等待接收消息....把接受到的消息打印在终端");
}
}
消费者 2 :
package com.run.rabbitmq.seven;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.run.rabbitmq.utils.RabbitMqUtils;
/**
* @Date: 2021/07/07/10:49
*
* 主题交换机 消费者 2
*/
public class ReceiveLogsTopic02 {
public static final String EXCHANGE_NAME = "topic_logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
//声明一个交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
//声明一个队列
String queueName = "Q2";
channel.queueDeclare(queueName,false,false,false,null);
//队列绑定交换机
channel.queueBind(queueName,EXCHANGE_NAME,"*.*.rabbit");
channel.queueBind(queueName,EXCHANGE_NAME,"lazy.#");
//接收消息
DeliverCallback deliverCallback = (consumerTag, message) -> {
System.out.println("ReceiveLogsTopic02 接收消息:"+new String(message.getBody()));
};
channel.basicConsume(queueName,true,deliverCallback, consumerTag -> {});
System.out.println("等待接收消息....把接受到的消息打印在终端");
}
}
生产者 :
package com.run.rabbitmq.seven;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.run.rabbitmq.utils.RabbitMqUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* @Date: 2021/07/07/10:49
*
* 主题交换机 生产者
*/
public class TopicLogs {
//交换机的名称
public static final String EXCHANGER_NAME = "topic_logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
channel.exchangeDeclare(EXCHANGER_NAME, BuiltinExchangeType.TOPIC);
Map<String,String> bindingKeyMap = new HashMap<>();
bindingKeyMap.put("quick.orange.rabbit","被队列 Q1Q2 接收到");
bindingKeyMap.put("lazy.orange.elephant","被队列 Q1Q2 接收到");
bindingKeyMap.put("quick.orange.fox","被队列 Q1 接收到");
bindingKeyMap.put("lazy.brown.fox","被队列 Q2 接收到");
bindingKeyMap.put("lazy.pink.rabbit","虽然满足两个绑定但只被队列 Q2 接收一次");
bindingKeyMap.put("quick.brown.fox","不匹配任何绑定不会被任何队列接收到会被丢弃");
bindingKeyMap.put("quick.orange.male.rabbit","是四个单词不匹配任何绑定会被丢弃");
bindingKeyMap.put("lazy.orange.male.rabbit","是四个单词但匹配 Q2");
for (Map.Entry<String, String> stringStringEntry : bindingKeyMap.entrySet()) {
String routingKey = stringStringEntry.getKey();
String message = stringStringEntry.getValue();
channel.basicPublish(EXCHANGER_NAME,routingKey,null,message.getBytes("UTF-8"));
System.out.println("生产者发出消息:"+message);
}
}
}