个人笔记
目录
Fanout Exchange(扇型交换机,又称广播交换机)
交换机
RabbitMQ的交换机类型共有四种,是根据其路由过程的不同而划分成的
分别是Direct Exchange(直连交换机), Fanout Exchange(扇型交换机,又称广播交换机), Topic Exchange(主题交换机)与 Headers Exchange(头交换机)
Direct Exchange(直连交换机):
在该图中,直连交换器X上绑定了两个队列。第一个队列绑定了绑定键orange,第二个队列有两个绑定键:black和green。在这种场景下,一个消息在布时指定了路由键为orange将会只被路由到队列Q1,路由键为black和green的消息都将被路由到队列Q2。其他的消息都将被丢失。
同一个绑定键可以绑定到不同的队列上去,在上图中,我们也可以增加一个交换器X与队列Q2的绑定键,在这种情况下,直连交换器将会和广播交换器有着相同的行为,将消息推送到所有匹配的队列。一个路由键为black的消息将会同时被推送到队列Q1和Q2。
发送者:
public class MqDirectSendHandler {
protected static final String QUEUE_NAME = "queue.hello";
protected static final String ROUTE_KEY_ONE = "route.key.hello1";
protected static final String ROUTE_KEY_TWO = "route.key.hello2";
protected static final String ROUTE_KEY_THREE = "route.key.hello3";
protected static final String EXCHANGE_NAME = "direct.hello";
public static void main(String[] args) throws IOException {
directExchangeMoreQueueSend();
}
public static void directExchangeMoreQueueSend() throws IOException {
Channel channel = MqConnectionUtils.getChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
String message = "hello world ";
for (int i = 0; i < 10; i++) {
String x = message;
String y = message;
String z = message;
x = "Route one " + x + i;
y = "Route two " + y + i;
z = "Route three " + z + i;
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_ONE, MessageProperties.MINIMAL_BASIC, x.getBytes(StandardCharsets.UTF_8));
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_THREE, MessageProperties.MINIMAL_BASIC, z.getBytes(StandardCharsets.UTF_8));
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_TWO, MessageProperties.MINIMAL_BASIC, y.getBytes(StandardCharsets.UTF_8));
}
System.out.println("end");
}
}
消费者:
public class MqDirectRecHandler {
protected static final String ROUTE_KEY_ONE = "route.key.hello1";
protected static final String ROUTE_KEY_TWO = "route.key.hello2";
protected static final String ROUTE_KEY_THREE = "route.key.hello3";
protected static final String EXCHANGE_NAME = "direct.hello";
public static void main(String[] args) throws IOException {
directRecBindMoreQueueRec();
}
public static void directRecBindMoreQueueRec() throws IOException {
Channel channel = MqConnectionUtils.getChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
String queue = channel.queueDeclare().getQueue();
channel.queueBind(queue,EXCHANGE_NAME,ROUTE_KEY_ONE);
channel.queueBind(queue,EXCHANGE_NAME,ROUTE_KEY_THREE);
channel.queueBind(queue,EXCHANGE_NAME,ROUTE_KEY_TWO);
DeliverCallback deliverCallback = (consumerTag, deliver) -> {
String message = new String(deliver.getBody(), StandardCharsets.UTF_8);
System.out.println("Direct监听者多队列绑定队列:" + message);
};
channel.basicConsume(queue, Boolean.TRUE, deliverCallback, consumerTag -> {
});
}
}
Fanout Exchange(扇型交换机,又称广播交换机)
生产者把消息发送到交换机后,由交换机发送给消费者队列。消费者队列如果想要接收到交换机里的消息,那么需要保证:队列绑定的交换机名称要和交换机一致,这个是广播模式的关键,路由key可以忽略,也是MQ后续所有模式最粗略的前提。
发送者:
public class MqFanoutSendHandler {
protected static final String QUEUE_NAME = "queue.hello";
protected static final String EXCHANGE_NAME_ONE = "fanout.hello1";
public static void main(String[] args) throws IOException {
fanoutExchangeQueueSend();
}
public static void fanoutExchangeQueueSend() throws IOException {
Channel channel = MqConnectionUtils.getChannel();
channel.exchangeDeclare(EXCHANGE_NAME_ONE, BuiltinExchangeType.FANOUT, Boolean.FALSE, Boolean.TRUE, null);
channel.exchangeDeclare(EXCHANGE_NAME_TWO, BuiltinExchangeType.FANOUT, Boolean.FALSE, Boolean.TRUE, null);
String message = "hello world ";
for (int i = 0; i < 10; i++) {
String x = message;
String y = message;
x = "交换机1:" + x + i;
y = "交换机2:" + y + i;
channel.basicPublish(EXCHANGE_NAME_ONE, "", MessageProperties.MINIMAL_BASIC, x.getBytes(StandardCharsets.UTF_8));
channel.basicPublish(EXCHANGE_NAME_TWO, "", MessageProperties.MINIMAL_BASIC, y.getBytes(StandardCharsets.UTF_8));
}
System.out.println("end");
}
}
消费者:
public class MqFanoutRecHandler {
protected static final String QUEUE_NAME = "queue.hello";
protected static final String EXCHANGE_NAME_ONE = "fanout.hello1";
protected static final String EXCHANGE_NAME_TWO = "fanout.hello2";
public static void main(String[] args) throws IOException {
fanoutOnlyRecBindQueueRec();
}
public static void fanoutOnlyRecBindQueueRec() throws IOException {
Channel channel = MqConnectionUtils.getChannel();
channel.exchangeDeclare(EXCHANGE_NAME_ONE, BuiltinExchangeType.FANOUT,Boolean.FALSE,Boolean.TRUE,null);
channel.exchangeDeclare(EXCHANGE_NAME_TWO, BuiltinExchangeType.FANOUT,Boolean.FALSE,Boolean.TRUE,null);
channel.queueDeclare(QUEUE_NAME,Boolean.FALSE,Boolean.FALSE,Boolean.TRUE,null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME_ONE,"");
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME_TWO,"");
DeliverCallback deliverCallback = (consumerTag, deliver) -> {
String message = new String(deliver.getBody(), StandardCharsets.UTF_8);
System.out.println("Fanout听风者:" + message);
};
channel.basicConsume(QUEUE_NAME, Boolean.TRUE,deliverCallback,consumerTag->{});
}
}
Topic Exchange(主题交换机)
主体模式其实就是在路由模式的基础上,支持了对key的通配符匹配(*号以及#号),以满足更加复杂的消息分发场景(“#” : 匹配一个或者多个字符,“*”:匹配一个字符)。
发送者:
public class MqTopicSendHandler {
protected static final String QUEUE_NAME = "topic.queue.hello";
protected static final String ROUTE_KEY_ONE = "quick.orange.rabbit";
protected static final String ROUTE_KEY_TWO = "lazy.orange.elephant";
protected static final String ROUTE_KEY_THREE = "quick.orange.fox";
protected static final String ROUTE_KEY_FOUR = "lazy.brown.fox";
protected static final String ROUTE_KEY_FIVE = "lazy.pink.rabbit";
protected static final String ROUTE_KEY_SIX = "quick.brown.fox";
protected static final String ROUTE_KEY_SEVEN = "大西瓜";
protected static final String EXCHANGE_NAME = "topic.hello";
public static void main(String[] args) throws IOException {
topicExchangeQueueSend();
}
public static void topicExchangeQueueSend() throws IOException {
Channel channel = MqConnectionUtils.getChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC, Boolean.FALSE,Boolean.TRUE,null);
String message = "hello world ";
for (int i = 0; i < 10; i++) {
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_ONE, MessageProperties.MINIMAL_BASIC, (ROUTE_KEY_ONE + " " + message + i).getBytes(StandardCharsets.UTF_8));
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_TWO, MessageProperties.MINIMAL_BASIC, (ROUTE_KEY_TWO + " " + message + i).getBytes(StandardCharsets.UTF_8));
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_THREE, MessageProperties.MINIMAL_BASIC, (ROUTE_KEY_THREE + " " + message + i).getBytes(StandardCharsets.UTF_8));
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_FOUR, MessageProperties.MINIMAL_BASIC, (ROUTE_KEY_FOUR + " " + message + i).getBytes(StandardCharsets.UTF_8));
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_FIVE, MessageProperties.MINIMAL_BASIC, (ROUTE_KEY_FIVE + " " + message + i).getBytes(StandardCharsets.UTF_8));
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_SIX, MessageProperties.MINIMAL_BASIC, (ROUTE_KEY_SIX + " " + message + i).getBytes(StandardCharsets.UTF_8));
channel.basicPublish(EXCHANGE_NAME, ROUTE_KEY_SEVEN, MessageProperties.MINIMAL_BASIC, (ROUTE_KEY_SEVEN + " " + message + i).getBytes(StandardCharsets.UTF_8));
}
System.out.println("end");
}
}
消费者:
public class MqTopicRecHandler {
protected static final String QUEUE_NAME = "topic.queue.hello";
protected static final String ROUTE_KEY_TOPIC_ONE = "#.rabbit";
protected static final String ROUTE_KEY_TOPIC_TWO = "*.orange.rabbit";
protected static final String ROUTE_KEY_TOPIC_THREE = "#.orange.*";
protected static final String ROUTE_KEY_TOPIC_FOUR = "#";
protected static final String EXCHANGE_NAME = "topic.hello";
public static void main(String[] args) throws IOException {
topicRecBindQueueRec();
}
public static void topicRecBindQueueRec() throws IOException {
Channel channel = MqConnectionUtils.getChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC, Boolean.FALSE, Boolean.TRUE, null);
channel.queueDeclare(QUEUE_NAME, Boolean.FALSE, Boolean.FALSE, Boolean.TRUE, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTE_KEY_TOPIC_TWO );
DeliverCallback deliverCallback = (consumerTag, deliver) -> {
String message = new String(deliver.getBody(), StandardCharsets.UTF_8);
System.out.println(message);
};
channel.basicConsume(QUEUE_NAME, Boolean.TRUE, deliverCallback, consumerTag -> {
});
}
}
Headers Exchange(头交换机)
Headers类型的exchange使用的比较少,以至于官方文档貌似都没提到,它是忽略routingKey的一种路由方式。是使用Headers来匹配的。Headers是一个键值对,可以定义成Hashtable。发送者在发送的时候定义一些键值对,接收者也可以再绑定时候传入一些键值对,两者匹配的话,则对应的队列就可以收到消息。
匹配有两种方式all和any。这两种方式是在接收端必须要用键值”x-mactch”来定义。all代表定义的多个键值对都要满足,any代表只要满足一个就可以。fanout,direct,topic exchange的routingKey都需要要字符串形式的,而headers exchange则没有这个要求,因为键值对的值可以是任何类型。
发送者:
public class MqHeaderSendHandler {
protected static final String EXCHANGE_NAME = "header.hello";
public static void main(String[] argv) throws Exception {
String message = "hello world";
Map<String, Object> headers = new HashMap<>(BaseConstant.SIX);
headers.put("hello","world");
try (Channel channel = MqConnectionUtils.getChannel()) {
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.HEADERS, Boolean.FALSE, Boolean.TRUE, null);
AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
//传递方式
builder.deliveryMode(MessageProperties.PERSISTENT_TEXT_PLAIN.getDeliveryMode());
//优先级
builder.priority(MessageProperties.PERSISTENT_TEXT_PLAIN.getPriority());
builder.headers(headers);
AMQP.BasicProperties props = builder.build();
channel.basicPublish(EXCHANGE_NAME,"", props, message.getBytes(StandardCharsets.UTF_8));
}
}
}
消费者:
public class MqHeaderRecHandler {
protected static final String EXCHANGE_NAME = "header.hello";
protected static final String QUEUE_NAME = "header.queue.hello";
public static void main(String[] argv) throws Exception {
Channel channel = MqConnectionUtils.getChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.HEADERS, Boolean.FALSE, Boolean.TRUE, null);
Map<String, Object> headers = new HashMap<>();
headers.put("hello", "world");
channel.queueDeclare(QUEUE_NAME, Boolean.FALSE, Boolean.FALSE, Boolean.TRUE, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "", headers);
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
System.out.println("接收消息"+ message);
};
channel.basicConsume(QUEUE_NAME, Boolean.TRUE, deliverCallback, consumerTag -> {
});
}
}