RabbitMQ使用场景
笔记
SpringBoot整合RabbitMQ
fanout模式
1.创建springboot项目添加依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.配置RabbitMQ连接
server.port=8081 spring.rabbitmq.username=guest spring.rabbitmq.password=guest spring.rabbitmq.virtual-host=/ spring.rabbitmq.host=localhost spring.rabbitmq.port=5672
3.添加RabbitMQ配置类(方式1:在发送消息端配置)
@Configuration public class RabbitMQConfig { // 1.声明fanout模式的交换机 @Bean public FanoutExchange fanoutExchange(){ return new FanoutExchange("fanout_order_exchange",true,false); } // 2.声明队列 sms,fanout,queue email,fanout,queue,phone,fanout,queue @Bean public Queue phoneQueue1(){ return new Queue("phone.fanout.queue",true); } @Bean public Queue smsQueue1(){ return new Queue("sms.fanout.queue",true); } @Bean public Queue emailQueue1(){ return new Queue("email.fanout.queue",true); } // 3.完成绑定关系(队列和交换机完成绑定关系) @Bean public Binding phoneBinding1(){ return BindingBuilder.bind(phoneQueue()).to(fanoutExchange()); } @Bean public Binding smsBinding1(){ return BindingBuilder.bind(smsQueue()).to(fanoutExchange()); } @Bean public Binding emailBinding1(){ return BindingBuilder.bind(emailQueue()).to(fanoutExchange()); } }
4.编写service类发送消息
@Service public class OrderService { @Autowired private RabbitTemplate rabbitTemplate; /** * 模拟用户下单 * @param userId * @param productId * @param num */ public void makeOrder_fanoutExchange(String userId,String productId,int num){ // 1.根据商品id查询库存是否充足 // 2.保存订单 String orderId = UUID.randomUUID().toString(); System.out.println("订单生产成功:" + orderId); // 3.通过MQ来完成消息 // 参数1:交换机 参数2:路由key/queue队列名称 参数3:消息内容8 // String exchangeName = "fanout_order_exchange"; String exchangeName = "fanout_order_exchange"; String routingKey = ""; rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId); } }
5.测试类
@Autowired private OrderService orderService; @Test void makeOrder_fanoutExchange1() { orderService.makeOrder_fanoutExchange("1","001",10); }
6.配置消息接收方(导入依赖)
server.port=8082 spring.rabbitmq.username=guest spring.rabbitmq.password=guest spring.rabbitmq.virtual-host=/ spring.rabbitmq.host=localhost spring.rabbitmq.port=5672
7.接收方监听队列,处理消息(每个类单独配置,单独绑定队列)
@Service @RabbitListener(queues = {"email.fanout.queue"}) public class EmailConsumer { @RabbitHandler public void receiveMessage(String msg){ System.out.println("Email_fanout->接收到了订单信息:" + msg); } } @Service @RabbitListener(queues = {"phone.fanout.queue"}) public class PhoneConsumer { @RabbitHandler public void receiveMessage(String msg){ System.out.println("Phone_fanout->接收到了订单信息:" + msg); } } @Service @RabbitListener(queues = {"sms.fanout.queue"}) public class SMSConsumer { @RabbitHandler public void receiveMessage(String msg){ System.out.println("SMS_fanout->接收到了订单信息:" + msg); } }
8.测试接收消息
1.消息发送方测试类启动 2.开启消息接收方主类 SpringbootOrderRabbitmqConsumerApplication
9.效果展示


切换direct模式
1.配置类
@Configuration public class RabbitMQConfig { /* 修改为direct路由模式 */ @Bean public DirectExchange directExchange(){ return new DirectExchange("direct_order_exchange",true,false); } // 2.声明队列 sms,fanout,queue email,fanout,queue,phone,fanout,queue @Bean public Queue phoneQueue(){ return new Queue("phone.direct.queue",true); } @Bean public Queue smsQueue(){ return new Queue("sms.direct.queue",true); } @Bean public Queue emailQueue(){ return new Queue("email.direct.queue",true); } // 3.完成绑定关系(队列和交换机完成绑定关系) @Bean public Binding phoneBinding(){ return BindingBuilder.bind(phoneQueue()).to(directExchange()).with("phone"); } @Bean public Binding smsBinding(){ return BindingBuilder.bind(smsQueue()).to(directExchange()).with("sms"); } @Bean public Binding smsBinding2(){ return BindingBuilder.bind(smsQueue()).to(directExchange()).with("phone"); } @Bean public Binding emailBinding(){ return BindingBuilder.bind(emailQueue()).to(directExchange()).with("email"); }
2.编写service类
@Service public class OrderService { public void makeOrder_directExchange(String userId,String productId,int num){ // 1.根据商品id查询库存是否充足 // 2.保存订单 String orderId = UUID.randomUUID().toString(); System.out.println("订单生产成功:" + orderId); // 3.通过MQ来完成消息 // 参数1:交换机 参数2:路由key/queue队列名称 参数3:消息内容8 // String exchangeName = "fanout_order_exchange"; String exchangeName = "direct_order_exchange"; String routingKey = "phone"; rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId); } }
3.测试类发送消息
@Test void makeOrder_directExchange1() { orderService.makeOrder_directExchange("2","007",11); }
4.接收方监听队列,处理消息(每个类单独配置,单独绑定队列)
@Service @RabbitListener(queues = {"email.direct.queue"}) public class EmailConsumer1 { @RabbitHandler public void receiveMessage(String msg){ System.out.println("Email_direct->接收到了订单信息:" + msg); } } @Service @RabbitListener(queues = {"phone.direct.queue"}) public class PhoneConsumer1 { @RabbitHandler public void receiveMessage(String msg){ System.out.println("Phone_direct->接收到了订单信息:" + msg); } } @Service @RabbitListener(queues = {"sms.direct.queue"}) public class SMSConsumer1 { @RabbitHandler public void receiveMessage(String msg){ System.out.println("SMS_direct->接收到了订单信息:" + msg); } }
5.测试接收消息
1.消息发送方测试类启动 2.开启消息接收方主类 SpringbootOrderRabbitmqConsumerApplication
6.效果展示


切换topic模式
1.配置路由与队列绑定(绑定的另一种方式,在消息接收端)
/** * 绑定路由与队列方式2 */ @Component @RabbitListener(bindings = @QueueBinding( value = @Queue(value = "topic_com_queue",durable = "true",autoDelete = "false"), exchange = @Exchange(value = "topic_order_exchange",type = ExchangeTypes.TOPIC), //默认是direct模式 key = "com.#" )) public class ComConsumer { @RabbitHandler public void receiveMessage(String message){ System.out.println("com_topic->接收到了订单信息:" + message); } } @Component @RabbitListener(bindings = @QueueBinding( value = @Queue(value = "topic_order_queue",durable = "true",autoDelete = "false"), exchange = @Exchange(value = "topic_order_exchange",type = ExchangeTypes.TOPIC), key = "*.order.*" )) public class OrderConsumer { @RabbitHandler public void receiveMessage(String message){ System.out.println("order_topic->接收到了订单信息:" + message); } } @Component @RabbitListener(bindings = @QueueBinding( value = @Queue(value = "topic_user_queue",durable = "true",autoDelete = "false"), exchange = @Exchange(value = "topic_order_exchange",type = ExchangeTypes.TOPIC), key = "#.user.#" )) public class UserConsumer { @RabbitHandler public void receiveMessage(String message){ System.out.println("user_topic->接收到了订单信息:" + message); } }
2.开启消息接收端主类
SpringbootOrderRabbitmqConsumerApplication
3.编写service类
public void makeOrder_topicExchange(String userId,String productId,int num){ // 1.根据商品id查询库存是否充足 // 2.保存订单 String orderId = UUID.randomUUID().toString(); System.out.println("订单生产成功:" + orderId); // 3.通过MQ来完成消息 // 参数1:交换机 参数2:路由key/queue队列名称 参数3:消息内容8 // String exchangeName = "fanout_order_exchange"; String exchangeName = "topic_order_exchange"; // com.# *.order.* #.user.# String routingKey = "com.order.user"; rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId); rabbitTemplate.convertAndSend(exchangeName,"com.order1.user",orderId); }
4.测试类测试
@Test void makeOrder_topicExchange(){ orderService.makeOrder_topicExchange("2","007",20); }
RabbitMQ进阶
1.过期时间TTL
过期时间TTL表示可以对消息设置预期的时间,在这个时间内都可以被消费者接收获取,过了之后消息将自动被删除,RabbitMQ可以对消息和队列设置TTL.目前有两种方法可以设置
第一种方法是通过队列属性设置,队列中所有消息都有相同的过期时间
1.配置TTL过期时间
/** * 设置TTL过期时间消息队列 */ @Configuration public class TTLRabbitMQConfig { // 1.声明交换机 @Bean public DirectExchange ttlDirectExchange(){ return new DirectExchange("ttl_direct_exchange",true,false); } // 2.声明队列 @Bean public Queue TTLDirectQueue(){ Map<String,Object> args = new HashMap<>(); args.put("x-message-ttl",10000); return new Queue("ttl.direct.queue",true,false,false,args); } // 3.完成绑定关系(队列和交换机完成绑定关系) @Bean public Binding TTLDirectBinding(){ return BindingBuilder.bind(TTLDirectQueue()).to(ttlDirectExchange()).with("ttl"); } }
2.service发送消息
/** * 给队列设置过期时间 * @param userId * @param productId * @param num */ public void makeOrder_TTL(String userId,String productId,int num){ // 1.根据商品id查询库存是否充足 // 2.保存订单 String orderId = UUID.randomUUID().toString(); System.out.println("订单生产成功:" + orderId); // 3.通过MQ来完成消息 // 参数1:交换机 参数2:路由key/queue队列名称 参数3:消息内容8 String exchangeName = "ttl_direct_exchange"; String routingKey = "ttl"; rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId); }
3.效果:

第二种方法是对消息进行单独设置,每条消息TTL可以不同
1.配置消息队列绑定交换机
/** * 设置TTL过期时间消息队列 */ @Configuration public class TTLRabbitMQConfig { // 1.声明fanout模式的交换机 @Bean public DirectExchange ttlDirectExchange(){ return new DirectExchange("ttl_direct_exchange",true,false); } @Bean public Queue TTLMessageQueue(){ return new Queue("ttl.message.direct.queue",true); } @Bean public Binding TTLMsgDirectBinding(){ return BindingBuilder.bind(TTLMessageQueue()).to(ttlDirectExchange()).with("ttlMessage"); } }
2.service发送消息
/** * 单独给消息设置过期时间 * @param userId * @param productId * @param num */ public void makeOrder_TTLMessage(String userId,String productId,int num){ // 1.根据商品id查询库存是否充足 // 2.保存订单 String orderId = UUID.randomUUID().toString(); System.out.println("订单生产成功:" + orderId); // 3.通过MQ来完成消息 // 参数1:交换机 参数2:路由key/queue队列名称 参数3:消息内容8 String exchangeName = "ttl_direct_exchange"; String routingKey = "ttlMessage"; MessagePostProcessor messagePostProcessor = new MessagePostProcessor() { @Override public Message postProcessMessage(Message message) throws AmqpException { message.getMessageProperties().setExpiration("10000"); message.getMessageProperties().setContentEncoding("UTF-8"); return message; } }; // 重载方法 rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId,messagePostProcessor); }
注:
两种方法同时使用时,消息的过期时间以两者之间TTL较小的那个数值为准,消息在队列的生存时间一旦超过设置的TTL值,就称为dead message被投递到死信队列,消费者将无法再收到该信息
死信队列(DLX)
>>接盘侠<<
当消息在一个队列中变成死信之后,它能被重新发送到另一个交换机中,这个交换机就是DLX,绑定DLX的队列就称之为死信队列,消息变成死信,可能原因有:
-
消息被拒绝
-
消息过期
-
队列达到最大长度
1.配置死信交换机和死信队列
/** * 配置信息交换机和队列 */ @Configuration public class DeadRabbitMQConfig { // 1.声明交换机 @Bean public DirectExchange deadDirectExchange(){ return new DirectExchange("dead_direct_exchange",true,false); } // 2.声明队列 @Bean public Queue DeadQueue(){ return new Queue("dead.direct.queue",true); } // 3.完成绑定关系(队列和交换机完成绑定关系) @Bean public Binding DeadDirectBinding(){ return BindingBuilder.bind(DeadQueue()).to(deadDirectExchange()).with("dead"); } }
2.消息队列关联死信队列
@Bean public Queue TTLDirectQueue(){ /* * 这里修改过参数重新启动会报错,因为队列不会覆盖设置的属性值, * 所以需要重新定义一个新的队列实现(开发中禁止删除已有队列[丢失信息]) * */ Map<String,Object> args = new HashMap<>(); // 设置过期时间 args.put("x-message-ttl",10000); // 设置队列消息的长度 如果产生的消息大于5条,那么就会往死信队列转移 // args.put("x-max-length","5"); // 设置死信交换机 args.put("x-dead-letter-exchange","dead_direct_exchange"); // 设置死信routerKey-->fanout模式不需要配置 args.put("x-dead-letter-routing-key","dead"); return new Queue("ttl.direct.queue",true,false,false,args); }
3.启动ttl测试类发送信息
@Test void makeOrder_TTL(){ orderService.makeOrder_TTL("TTL","A001",10); }
4.测试结果

时间花在哪里,成就就在哪里

浙公网安备 33010602011771号