首先了解RabbitMQ的一些名词
- Broker: 简单来说就是消息队列服务器实体
- Exchange: 消息交换机,它指定消息按什么规则,路由到哪个队列
- Queue: 消息队列载体,每个消息都会被投入到一个或多个队列
- Binding: 绑定,它的作用就是把exchange和queue按照路由规则绑定起来
- Routing Key: 路由关键字,exchange根据这个关键字进行消息投递
- VHost: vhost 可以理解为虚拟 broker ,即 mini-RabbitMQ server。其内部均含有独立的 queue、exchange 和 binding 等,但最最重要的是,其拥有独立的权限系统,可以做到 vhost 范围的用户控制。当然,从 RabbitMQ 的全局角度,vhost 可以作为不同权限隔离的手段(一个典型的例子就是不同的应用可以跑在不同的 vhost 中)。
- Producer: 消息生产者,就是投递消息的程序
- Consumer: 消息消费者,就是接受消息的程序
- Channel: 消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务
RabbitMQ的工作模式
1, simple模式, 消息生产者直接将消息加入到队列中, 消息消费者监听消息队列, 如果队列有消息, 就消费掉, 消息被拿走后会自动删除, 但有可能消息并没有被消费者正确处理, 但消息却已经消失了, 造成消失丢失, 解决: 在消息正确处理后手动确认, 注意要即时, 否则会造成内存溢出
@Component
@RabbitListener(queuesToDeclare = @Queue("hello")) //接收hello队列的消息
public class HelloCustomer {
@RabbitHandler
public void receivel(String message) {
System.out.println("message = "+message);
}
}
2, work工作模式: 消息产生者将消息放入队列, 消费者可以有多个, 消费者1,消费者2同时监听同一个队列, 消息被生成后, C1 C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息, 默认情况是平均分配的, 问题: 高并发下会产生一个消息被多个消费者同时消费, 需要设置一个锁, 保证一条消息只能被一个消费者消费
@Component
public class WorkCustomer {
/**
* 多个消费者同时消费一个队列的信息
* @param message
*/
@RabbitListener(queuesToDeclare = @Queue("work"))
public void receivel1(String message) {
System.out.println("message1 = "+ message);
}
@RabbitListener(queuesToDeclare = @Queue("work"))
public void receivel2(String message) {
System.out.println("message2 = "+ message);
}
}
3, fanout广播模式: 每个消费者监听自己的队列, 且每个队列绑定交换机, 生产者将消息发送给交换机, 由交换机将消息发送给绑定的队列
@Component
public class FanoutCustomer {
//无路由key, 定义交换机类型为广播类型, 所有绑定交换机的消费者都可消费队列中信息
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs", type = "fanout")
)
})
public void receivel1(String message) {
System.out.println("message1 = " + message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs", type = "fanout")
)
})
public void receivel2(String message) {
System.out.println("message2 = " + message);
}
}
4, routing路由模式: 此时队列与交换机的绑定需要指定一个Routing key, 而且交换机也不是将消息发送给所有绑定的队列, 而且发送给Routing key与交换机的Routing key匹配的队列
@Component
public class RouteCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue, //创建一个临时队列
exchange = @Exchange(value = "direct", type = "direct"), //定义交换机的值和类型
key = {"info", "error"} //路由key, 只能接收固定路由key的信息
)
})
public void receivel1(String message) {
System.out.println("message1 = " + message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "direct", type = "direct"),
key = {"error"}
)
})
public void receive2(String message) {
System.out.println("message1 = " + message);
}
}
5, topic 主题模式(路由模式的一种): 在路由模式的基础上添加了Routing key的通配符功能
@Component
public class TopicCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "topic", type = "topic"),
key = "user.*"
)
})
public void receivel(String message) {
System.out.println("message = " + message);
}
}
对应工作模式的发送消息的测试
@SpringBootTest(classes = yxy.cart.DemoApplication.class)
public class TestMQ {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void simple() {
rabbitTemplate.convertAndSend("hello", "hello world");
}
@Test
public void work() {
for (int i = 0; i < 10; i++) {
rabbitTemplate.convertAndSend("work", "work的消息");
}
}
@Test
public void fanout() {
rabbitTemplate.convertAndSend("logs","", "fanout");
}
@Test
public void route() {
rabbitTemplate.convertAndSend("direct","info", "direct");
}
@Test
public void topic() {
rabbitTemplate.convertAndSend("topic","user.save", "topic");
}
}