RabbitMQ消息模型的核心组件
- 消息生产者(Producer)
- 定义:生产者是负责生成并发送消息的应用程序。
- 功能:生产者将消息发送到交换器,交换器再根据特定的路由规则将消息分发到队列。
- 消息消费者(Consumer)
- 定义:消费者是接收并处理消息的应用程序。
- 功能:消费者从队列中获取消息并执行相应的业务逻辑,处理完毕后可以确认消息的消费。
- 消息(Message)
- 定义:消息是生产者发送的一个包含数据的包。
- 组成:消息主要由两部分构成:
- 消息体(Body):包含实际的数据内容。
- 消息头(Header):包含元数据,如路由键、消息属性等。
- 队列(Queue)
- 定义:队列是一个用于存储消息的缓冲区,消费者从中读取消息进行处理。
- 功能:队列确保消息按发送顺序存储,并提供可靠的消息持久化机制。
- 交换器(Exchange)
- 定义:交换器接收来自生产者的消息,并根据绑定和路由键将消息路由到一个或多个队列。
- 路由键(Routing Key)
- 定义:路由键是一个字符串,用于交换机将消息路由到特定队列。
- 功能:通过路由键,生产者可以指定消息的目标队列。
- 绑定(Binding)
- 定义:绑定是交换机和队列之间的链接,定义了消息如何从交换机到达队列。
- 功能:绑定包含路由规则,决定消息路由路径。
RabbitMQ消息模型
-
基本消息队列(BasicQueue)
工作流程
- 生产者将消息发送到队列。
- 消费者从队列中读取消息并处理。
- 消息在被消费后从队列中移除。
代码示例
注意在实现这些功能前需要导入SpringAMQP依赖
生产者代码
@SpringBootTest public class SpringAmqpTest{ //自动装配RabbitTemplate模板对象 @Autowired private RabbitTemplate rabbitTemplate; /** * Basic Queue简单队列模型 */ @Test public void testSimpleQueue(){ //1.定义变量保存队列名 String queueName = "simple.queue"; //2.定义变量保存发送的消息 String message = "hello,world!"; //3.发送消息 rabbitTemplate.convertAndSend(queueName, message); } }消费者代码
@Component public class SpringRabbitListener{ //定义监听简单消息队列simple.queue的消息 /* 1.RabbitListener 注解中的属性:String[] queues() default{}; 书写监听哪个队列的名字 */ @RabbitListener(queues = "simple.queue") public void listenSimpleMessage(String msg){ System.out.println("yes, I know" + msg); } } -
工作队列模式(WorkQueue)
工作流程
- 生产者将任务消息发送到队列。
- 多个消费者监听同一个队列,分摊处理任务。
- 任务在被消费后从队列中移除。
代码示例
生产者代码
/* * workQueue * 向队列中不停发送消息,模拟消息堆积。 */ @Test @RabbitListener(queuesToDeclare = @Queue("work.queue")) public void testWorkQueue() throws InterruptedException{ // 1.定义变量保存存放消息的队列名 String queueName = "work.queue"; //2.定义变量保存发送的消息 String message = "hello, world"; //3.发送消息 for(int i = 1; i <= 60; i++){ rabbitTemplate.convertAndSend(queueName, message + i); //每隔20毫秒发送 Thread.sleep(20); } }消费者代码
//定义消费者1消费工作队列的消息 @RabbitListener(queues = "work.queue") public void listenWork1Message(String msg) throws InterruptedException{ System.out.println("消费者1接收到" + msg); //休眠20ms Thread.sleep(20); } //定义消费者2消费工作队列的消息 @RabbitListener(queues = "work.queue") public void listenWork2Message(String msg) throws InterruptedException{ System.out.println("消费者2接收到" + msg); //休眠20ms Thread.sleep(20); } -
发布订阅(Publish、Subscribe),又根据交换机类型不同分为三种:
- 广播
工作流程
-
生产者将消息发送到交换器。
-
多个队列订阅交换器,接收消息。
-
每个队列的消费者从队列中获取消息并处理。
代码示例
生产者代码
/** * Fanout Exchange:广播 */ @Test public void testFanoutExchange(){ //1.定义变量保存交换机的名字 String exchangeName="change.fanout"; //2.定义变量保存发送的消息 String message="hello,world!"; //3.发送消息 //第二个参数routingkey,这里实现的是广播交换机,不需要routingkey,因此这里是空字符串 rabbitTemplate.convertAndSend(exchangeName,"",message); }消费者代码
配置类实现方式:
Config
/* * @Configuration 将修饰的类FanoutConfig对象放到SpringIOC容器中 */ @Configuration public class FanoutConfig{ //1.定义方法生命交换机,将交换机对象放到SpringIOC容器中 //@Bean修饰的方法返回值对象作为SpringIOC容器中的value,方法名作为key @Bean public FanoutExchange fanoutExchange(){ //change.fanout表示交换器的名字 return new FanoutExchange("change.fanout"); } //2.定义方法声明队列1 @Bean public Queue fanoutQueue1(){ //fanout.queue1 表示队列名 return new Queue("fanout.queue1"); } //3.定义方法将队列1绑定到交换机change.fanout上 //下面方法的形参FanoutExchange fanoutExchange的名字和上述 public FanoutExchange fanoutExchange(){}方法名一致 @Bean public Bingding bingingQueue1ToExchange(FanoutExchange fanoutExchange, Queue fanoutQueue1){ /* public Binding to(FanoutExchange exchange){} */ return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange); } //4.定义方法声明队列2 @Bean public Queue fanoutQueue2(){ //fanout.queue2 表示队列名 return new Queue("fanout.queue2"); } //5.定义方法将队列2绑定到交换机上 @Bean public Binding bindingQueue2ToExchange(FanoutExchange fanoutExchange,Queue fanoutQueue2){ /* public Binding to(FanoutExchange exchange){} */ return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange); } }消费者代码
@RabbitListener(queues = "fanout.queue1") public void listenFanout1Message(String msg){ System.out.println("消费者1接收到了生产者发送的消息:"+msg); } @RabbitListener(queues = "fanout.queue2") public void listenFanout2Message(String msg){ System.out.println("消费者2接收到了生产者发送的消息:"+msg); } -
路由交换机实现
工作流程
- 生产者将消息发送到交换器,指定路由键。
- 队列通过绑定路由键订阅交换器。
- 交换器根据路由键将消息路由到相应的队列。
代码示例
生产者代码
/**
* Direct Exchange:路由
*/
@Test
public void testSendDirectExchange(){
//1.定义变量保存交换机名
String exchangeName = "exchange.direct";
//2.定义变量保存消息
String message="hello,world!";
//3.发送消息 "one" 路由key
rabbitTemplate.convertAndSend(exchange, "one", message);
}
消费者代码
/*
*队列1
*1.@RabbitListener 注解的属性:QueueBinding[] bindings() default{};
说明:QueueBingding也是一个注解,表示队列绑定,当前队列和哪个交换机绑定
2.@QueueBinding注解中常见属性
1)Queue value(); 属于Queue,Queue是一个注解,在Queue注解中有一个属性name,name属性值表示书写的队列名
value=@Queue(name="direct.queue1") ===>direct.queue1 表示队列名
2)Exchange exchange();属于Exchange类型,是一个注解,在Exchange注解中有属性
I:String name() default ""; 表示交换机的名字 name="change.direct"==》change.direct是交换机名字
II:String type() default "direct" 表示交换机类型===> ExchangeTypes.DIRECT就是"direct"
3)String[] key() default{}; 表示绑定的routing key ===> key={"one", "two"}
*/
@RabbitListener(bindings = {@QueueBinding(value=@Queue(name="direct.queue1"),
exchange = @Exchange(name="exchange.direct", type = ExchangeTypes.DIRECT), key={"one", "two"})})
public void listenDirect1Message(String msg){
System.out.println("消费者1收到" + msg);
}
/*
*队列2
*/
@RabbitListener(bindings = {@QueueBinding(value=@Queue(name="direct.queue2"),
exchange = @Exchange(name="exchange.direct", type = ExchangeTypes.DIRECT), key={"two", "three"})})
public void listenDirect1Message(String msg){
System.out.println("消费者2收到" + msg);
}
- 主题交换机实现
工作流程
- 生产者将消息发送到交换器,指定模式匹配的路由键。
- 队列通过绑定模式匹配的路由键订阅交换器。
- 交换器根据模式匹配的路由键将消息路由到相应的队列。
代码示例
生产者代码
/**
* Topic Exchange:主题
*/
@Test
public void testSendTopicExchange() {
//1.定义变量保存交换机名
String exchangeName = "exchange.topic";
//2.定义变量保存消息
String message="hello world";
//3.发送消息 one.message 表示routing key
rabbitTemplate.convertAndSend(exchangeName,"one.message",message);
}
消费者代码
/*
定义方法模拟队列1接收主题topic交换机的消息
key={"one.#"} 表示routing key 这里#表示大于等于0个字符
*/
@RabbitListener(bindings = @QueueBinding(
value=@Queue(name="topic.queue1"),
exchange = @Exchange(name="exchange.topic",type= ExchangeTypes.TOPIC),
key={"one.#"}
))
public void listenTopic1Message(String msg){
System.out.println("消费者1接收"+msg);
}
/*
TODO: key={"#.one"} #表示大于等于个字符,发送者发送的routingkey只要以one结尾就会将消息路由到当前队列
*/
@RabbitListener(bindings = @QueueBinding(
value=@Queue(name="topic.queue2"),
exchange = @Exchange(name="itcast.topic",type= ExchangeTypes.TOPIC),
key={"#.news"}
))
public void listenTopic2Message(String msg){
System.out.println("消费者2接收到了生产者发送的消息:"+msg);
}