基本概念
Publisher(发布者)
发布者 (或称为生产者) 负责生产消息并将其投递到指定的交换器上。
Consumer(消费者)
消费者, 消费生产者产生的消息。
Exchange(交换器)
接收Producer发来的消息, 并转发到对应的 Queue, RabbitMQ 有四种类型的 Exchange , 不同类型的 Exchange 对消息的转发方式不同。
- Direct Exchange: Direct Exchange 会对消息的 routing key 和 Queue 绑定到 Exchange 的 binding key 比对, 将消息转发给完全匹配(等值)的 Queue 。即 Queue 的 binding key = routing key 。如下图,当消息的 RountingKey 为 orange 时,消息会被路由到 Q1 队列;当消息的 RountingKey 为 black 或 green 时,消息会被路由到 Q2 队列。
一个交换器绑定多个队列时,它们的 BindingKey 是可以相同的,如下图。此时当消息的 RountingKey 为 black 时,消息会同时被路由到 Q1 和 Q2 队列。
-
Topic Exchange: Topic Exchange 运行将 routing key 和 binding key 进行通配符匹配。
routing key 和 binding key 由多个单词使用
.
进行连接- BindingKey 支持两个特殊符号:
#
和*
。其中*
用于匹配一个单词,#
用于匹配零个或者多个单词。
以下是官方文档中的示例,交换器与队列的绑定情况如图所示,此时的路由情况如下:
-
路由键为
lazy.orange.elephant
的消息会发送给所有队列; -
路由键为
quick.orange.fox
的消息只会发送给 Q1 队列; -
路由键为
lazy.brown.fox
的消息只会发送给 Q2 队列; -
路由键为
lazy.pink.rabbit
的消息只会发送给 Q2 队列; -
路由键为
quick.brown.fox
的消息与任何绑定都不匹配; -
路由键为
orange
或quick.orange.male.rabbit
的消息也与任何绑定都不匹配。
- BindingKey 支持两个特殊符号:
-
Fanout Exchange: Fanout Exchange 是消息广播的模式, 不会去匹配路由键,直接把消息投递到所有绑定到 fanout 交换器中的队列</上,它就像一个广播站一样,它会向所有收听广播的用户发送消息。
-
Headers Exchange(极少使用)
###Queue(消息队列)
存储消息的队列。其通过 binding key 与 Exchange 绑定。
Routing Key(路由键)
消息的一个属性,可以看作是消息的类型(根据业务自定义),比如将程序不同级别的日志作为消息发送时,error级别的消息就可以使用 log.error 作为 routing key。
Binding Key(绑定键)
Queue 与 Exchang 绑定时的一个属性,可以看作 Queue 对哪种类型的业务消息感兴趣, Exchange会根据消息的 routing key 和 binding key 决定是否将该消息转发给一个 Queue。
Virtual Host(虚拟主机)
RabbitMQ 通过虚拟主机来实现逻辑分组和资源隔离, 可以认为每个虚拟主机是一个独立的命名空间, 拥有独立的队列、交换器和绑定关系。用户可以按照不同业务场景建立不同的虚拟主机,虚拟主机之间是完全独立的,你无法将 vhost1 上的交换器与 vhost2 上的队列进行绑定,这可以极大的保证业务之间的隔离性和数据安全。默认的虚拟主机名为 /
。
Spring Boot 整合 RabbitMQ
1、引入依赖
Spring Boot 集成 RabbitMQ 非常简单,如果只是简单的使用配置非常少,Spring Boot 提供了spring-boot-starter-amqp
项目对消息各种支持。
<!--rabbbitMQ相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2、配置 RabbitMQ 服务器连接地址、端口号、账号、密码
# rabbitmq服务器连接端口 (默认为5672)
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
注: guest为rabbitmq的默认用户名和密码, 只能登陆本机的rabbitmq服务器, 若mq非本机部署的情况下, 需要添加用户并设置用户权限。
3、添加 RabbitMQ 配置类, 配置Queue、Exchange、Binding
@Configuration
public class RabbitMQConfig {
/**
* 用于接收warn级别的日志消息的队列
* @return
*/
@Bean
public Queue warnQueue() {
// 参数为队列的name, 其等价于 new Queue(name, true, false, false)
// 即:durable = true, exclusive = false, autoDelete = false
return new Queue("warn.queue");
}
/**
* 用于接收error级别的日志消息的队列
* @return
*/
@Bean
public Queue errorQueue() {
return new Queue("error.queue");
}
/**
* 用于接收所有级别的日志消息的队列
* @return
*/
@Bean
public Queue allQueue() {
return new Queue("all.queue");
}
/**
* 创建一个交换机
* @return
*/
@Bean
public TopicExchange topicExchange(){
// 参数为exchange的名称, 其等价于 new TopicExchange(name, true, false)
// 即:durable = true, autoDelete = false
return new TopicExchange("log.topic.exchange");
}
@Bean
public Binding binding(){
// 将队列于交换机绑定, 绑定三要素: Queue, Exchange, Binding Key
return BindingBuilder.bind(warnQueue()).to(topicExchange()).with("log.warn");
}
@Bean
public Binding binding1(){
return BindingBuilder.bind(errorQueue()).to(topicExchange()).with("log.error");
}
/**
* 使用log.*来匹配log.warn和log.error的日志消息
* @return
*/
@Bean
public Binding binding2(){
return BindingBuilder.bind(allQueue()).to(topicExchange()).with("log.*");
}
}
注: 发送消息时会在rabbitmq服务器中创建这里配置的Queue、 Exchange、Binding。
4、发送消息
发送消息使用 AmqpTemplate ,直接注入即可。
@RunWith(SpringRunner.class)
@SpringBootTest
public class SenderTest {
@Autowired
private AmqpTemplate amqpTemplate;
@Test
public void sendWarnLog(){
// 参数依次为: 目标exchange, 消息的routingKey, 消息体
amqpTemplate.convertAndSend("log.topic.exchange", "log.warn", "this is a warn log");
}
}
运行测试方法成功发送消息, 我们可以通过 rabbitmq 的控制台来查看:
图中可以看到我们配置的三个队列以及交换机已经创建成功, 并且我们发送的警告级别的日志消息已经被转发到了 all.queue 和 warn.queue 中。
5、消费消息
@Service
@Slf4j
public class Consumer {
/**
* 指定消费的队列
*/
@RabbitListener(queues = "warn.queue")
public void consume(String message){
log.info("消费消息: {}", message);
}
}
注: 示例中发送的消息为字符串类型, 若要发送对象, 对象需要实现Serializable接口。