文章学习Demo为springboot(八):RabbitMQ详解
1.Windows安装RabbitMQ
首先需要安装ErLang语言支持,再安装RabbitMQ(因为RabbitMQ是使用ErLang语言编写的)。启动RabbitMQ服务直接去D:\软件安装包\RabbitMQ\rabbitmq_server-3.7.4\sbin文件下,双击rabbitmq-server.bat即可。
运行成功如下所示:
RabbitMQ核心知识:交换机,路由键
exchange交换机机制
什么是交换机
rabbitmq的message model实际上消息不直接发送到queue中,中间有一个exchange是做消息分发,producer甚至不知道消息发送到那个队列中去。因此,当exchange收到message时,必须准确知道该如何分发。是append到一定规则的queue,还是append到多个queue中,还是被丢弃?这些规则都是通过exchagne的4种type去定义的。
The core idea in the messaging model in RabbitMQ is that the producer never sends any messages directly to a queue. Actually, quite often the producer doesn't even know if a message will be delivered to any queue at all.
Instead, the producer can only send messages to an exchange. An exchange is a very simple thing. On one side it receives messages from producers and the other side it pushes them to queues. The exchange must know exactly what to do with a message it receives. Should it be appended to a particular queue? Should it be appended to many queues? Or should it get discarded. The rules for that are defined by the exchange type.
exchange是一个消息的agent,每一个虚拟的host中都有定义。它的职责是把message路由到不同的queue中。
binding?
exchange和queue通过routing-key关联,这两者之间的关系是就是binding。如下图所示,X表示交换机,红色表示队列,交换机通过一个routing-key去binding一个queue,routing-key有什么作用呢?看Direct exchange类型交换机。
Directed Exchange
路由键exchange,该交换机收到消息后会把消息发送到指定routing-key的queue中。那消息交换机是怎么知道的呢?其实,producer deliver消息的时候会把routing-key add到 message header中。routing-key只是一个messgae的attribute。
A direct exchange delivers messages to queues based on a message routing key. The routing key is a message attribute added into the message header by the producer. The routing key can be seen as an "address" that the exchange use to decide how to route the message. A message goes to the queue(s) whose binding key exactly matches the routing key of the message.
Default Exchange
这种是特殊的Direct Exchange,是rabbitmq内部默认的一个交换机。该交换机的name是空字符串,所有queue都默认binding 到该交换机上。所有binding到该交换机上的queue,routing-key都和queue的name一样。
Topic Exchange
通配符交换机,exchange会把消息发送到一个或者多个满足通配符规则的routing-key
的queue。其中表号匹配一个word,#匹配多个word和路径,路径之间通过.隔开。如满足a..c的routing-key有a.hello.c;满足#.hello的routing-key有a.b.c.helo。
Fanout Exchange
扇形交换机,该交换机会把消息发送到所有binding到该交换机上的queue。这种是publisher/subcribe模式。用来做广播最好。
所有该exchagne上指定的routing-key都会被ignore掉。
The fanout copies and routes a received message to all queues that are bound to it regardless of routing keys or pattern matching as with direct and topic exchanges. Keys provided will simply be ignored.
Header Exchange
设置header attribute参数类型的交换机。
2.Demo核心知识
2.1 RabbitMQ默认连接信息为:
spring-boot下的application.properties文件
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
2.2 最简单的HelloTest:
发送者:
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class HelloSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send() {
String context = "hello " + "JadenOliver";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("hello", context);
}
}
接收者:
@Component
@RabbitListener(queues = "hello")
public class HelloReceiver {
@RabbitHandler
public void process(String hello) {
System.out.println("Receiver : " + hello);
}
}
注意点:
1>发送者和接收者的queue name必须一致,不然不能接收;(本例中为"hello")
2>接收者接收信息的队列名称为:"hello":如果这个"hello"队列没有自定义生成,RabbitMQ会默认去生成,亲测。
2.3 一对多发送和多对多发送:
一对多发送:一个发送者,多个接收者。结果:多个接收者均匀接收
Receiver 1: spirng boot neo queue ****** 84
Receiver 1: spirng boot neo queue ****** 86
Receiver 2: spirng boot neo queue ****** 85
Receiver 2: spirng boot neo queue ****** 88
Receiver 1: spirng boot neo queue ****** 87
Receiver 2: spirng boot neo queue ****** 89
Receiver 1: spirng boot neo queue ****** 90
Receiver 2: spirng boot neo queue ****** 91
Receiver 1: spirng boot neo queue ****** 92
Receiver 2: spirng boot neo queue ****** 93
Receiver 1: spirng boot neo queue ****** 94
Receiver 2: spirng boot neo queue ****** 95
Receiver 1: spirng boot neo queue ****** 96
Receiver 2: spirng boot neo queue ****** 97
Receiver 1: spirng boot neo queue ****** 98
Receiver 2: spirng boot neo queue ****** 99
多对多发送:多个发送者,多个接收者。结果:多个接收者均匀接收
Receiver 1: spirng boot neo queue ****** 93
Receiver 2: spirng boot neo queue ****** 93
Receiver 1: spirng boot neo queue ****** 94
Receiver 2: spirng boot neo queue ****** 94
Receiver 1: spirng boot neo queue ****** 95
Receiver 2: spirng boot neo queue ****** 95
Receiver 1: spirng boot neo queue ****** 96
Receiver 2: spirng boot neo queue ****** 96
Receiver 1: spirng boot neo queue ****** 97
Receiver 2: spirng boot neo queue ****** 97
Receiver 1: spirng boot neo queue ****** 98
Receiver 2: spirng boot neo queue ****** 98
Receiver 1: spirng boot neo queue ****** 99
Receiver 2: spirng boot neo queue ****** 99
2.4 消息队列高级使用:发送对象类型
发送对象不需要额外配置,和发送普通数据类型类似
//发送者
public void send(User user) {
System.out.println("Sender object: " + user.toString());
this.rabbitTemplate.convertAndSend("object", user);
}
...
//接收者
@RabbitHandler
public void process(User user) {
System.out.println("Receiver object : " + user);
}
结果:
Sender object: User{name='neo', pass='123456'}
Receiver object : User{name='neo', pass='123456'}
Topic交换机使用
topic 是RabbitMQ中最灵活的一种方式,可以根据routing_key自由的绑定不同的队列
首先对topic规则配置,这里使用两个队列来测试
@Configuration
public class TopicRabbitConfig {
final static String message = "topic.message";
final static String messages = "topic.messages";
@Bean
public Queue queueMessage() {
return new Queue(TopicRabbitConfig.message);
}
@Bean
public Queue queueMessages() {
return new Queue(TopicRabbitConfig.messages);
}
@Bean
TopicExchange exchange() {
return new TopicExchange("exchange");
}
@Bean
Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
}
@Bean
Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
}
}
说明:
1> queueMessage和queueMessages两个队列,都和exchange交换机关联起来;
2> 路由键对应分发:如果路由键满足"topic.message",exchange交换机把消息发送到queueMessage队列;
如果路由键匹配"topic.#"模式,exchange交换机把消息发送到queueMessages队列。
这个交换机和路由键的配置极大的提高了RabbitMQ的灵活性。
public void send1() {
String context = "hi, i am message 1";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("exchange", "topic.message", context);
}
public void send2() {
String context = "hi, i am messages 2";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("exchange", "topic.messages", context);
}
发送send1会匹配到topic.#和topic.message 两个Receiver都可以收到消息,发送send2只有topic.#可以匹配所有只有Receiver2监听到消息