rabbit

RabbitMQ

基于amqp协议

四种场景

  • 异步处理

用户注册后,需要发送邮件和短信,两种方式:

1.串行:一个一个发

2.并行:两个同时发

  • 应用解耦

将订单与库存的解耦

  • 流量削峰

用在秒杀活动

  • 消息通信

五种队列

配置

 //连接的主机
 spring.rabbitmq.host=8.130.102.114
 //端口
 spring.rabbitmq.port=5672
 //用户名
 spring.rabbitmq.username=admin
 //密码
 spring.rabbitmq.password=admin
 spring.rabbitmq.virtual-host=/
 
  1. helloword

默认交换机 一个生产者发送消息到队列一个消费者接收

  • 生产者

 //生产者创建队列 消费者也可
 @Configuration
 public class RabbitMQConfig {
    @Bean
    public Queue queue(){
        Queue queue = new Queue("spb-hello");
        return queue;
    }
 }
  • 消费者

 //消费者消费消息   
 @Component
 public class Listen {
 
  //监听的消息队列
    @RabbitListener(queues = "spb-hello")
    public void one(String msg){
        System.out.println(msg);
    }
  }  
  1. Work queue

默认交换机 一个生产者发送消息到队列多个消费者接收(抢)

  • 生产者

 同上
  • 消费者

 同上两个
  1. Publish

一个生产者发送到交换机 交换机绑定队列 队列给多个消费者推送消息(同时)

  • 生产者

 @Configuration
 public class PublishConfig {
  //第一个队列
    @Bean("sms-queue")
    public Queue smsQueue(){
        return new Queue("publish-sms-queue");
    }
    //第二个队列
    @Bean("email-queue")
    public Queue emailQueue(){
        return new Queue("publish-email-queue");
    }
 
    /**
      * 发布订阅交换机
      * @return
      */
    @Bean
    public FanoutExchange exchange(){
        return new FanoutExchange("sms-email-publish-exchange");
    }
 
  //绑定第一个队列
    @Bean
    Binding bindSmsToExchange(@Qualifier("sms-queue") Queue queue, FanoutExchange fanoutExchange){
      return   BindingBuilder.bind(queue).to(fanoutExchange);
    }
    //绑定第二个队列
    @Bean
    Binding bindEmailToExchange(@Qualifier("email-queue") Queue queue, FanoutExchange fanoutExchange){
        return   BindingBuilder.bind(queue).to(fanoutExchange);
    }
 
 }
 
  • 消费者

 同上监听队列得到信息
  1. Routing

一个生产者发送到交换机 交换机绑定队列 队列给多个消费者推送消息 通过关键词来判断队那个队列接收

  • 生产者

 @Configuration
 public class RoutingConfig {
 //第一个队列
 @Bean("smsqueue")
    public Queue smsqueue(){
    return new Queue("routing-sms-queue");
 }
  //第二个队列
    @Bean("emailqueue")
    public Queue emailqueue(){
        return new Queue("routing-email-queue");
    }
    //交换机
    @Bean
    public DirectExchange exchange(){
    return new DirectExchange("routing-email-sms-diret");
    }
    //绑定第一个队列设置关键词
    @Bean
    Binding smsbinding(@Qualifier("smsqueue") Queue queue, DirectExchange exchange){
    return BindingBuilder.bind(queue).to(exchange).with("sms");
    }
    //绑定第二个队列设置关键词
    @Bean
    Binding emailbinding(@Qualifier("emailqueue") Queue queue, DirectExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("email");
    }
    //同时绑定第一个第二个队列设置关键词
    @Bean
    Binding smsemailbinding(@Qualifier("smsqueue") Queue queue, DirectExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("sms.email");
    }
    @Bean
    Binding emailsmsbinding(@Qualifier("emailqueue") Queue queue, DirectExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("sms.email");
    }
 }
 
 
  //发消息通过关键字给指定队列发送
    @Test
    public void producerPublish(){
        rabbitTemplate.convertAndSend("sms-email-publish-exchange","sms","这是短信服务");
    }
 
  • 消费者

 同上
  1. Topics

一个生产者发送到交换机 交换机绑定队列 队列给多个消费者推送消息 通过关键词来判断队那个队列接收

关键词改变

'*' 代表一个单词

'#' 代表 0个 或 多个 单词

  • 生产者

 @Configuration
 public class TopicConfig {
  //队列1
    @Bean("smsqueue")
    public Queue smsqueue(){
        return new Queue("topic-sms-queue");
    }
    //队列2
    @Bean("emailqueue")
    public Queue emailqueue(){
        return new Queue("topic-email-queue");
    }
    //交换机
    @Bean
    public TopicExchange exchange(){
        return new TopicExchange("topic-sms-email-topic");
    }
    //绑定队列1
    @Bean
    Binding smsbind(@Qualifier("smsqueue") Queue queue, TopicExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("sms.#");
    }
    //绑定队列二
    @Bean
    Binding emailbind(@Qualifier("emailqueue") Queue queue, TopicExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("#.email");
    }
     
     
    //发消息
  //同时绑定只需发消息时同时满足两个队列的关键词
  @Test
    public void producerTopic2(){
        rabbitTemplate.convertAndSend("topic-sms-email-topic","sms.email","这是短信+邮箱+topic");
    }
 }
 
  • 消费者

 同上

消息确认机制

  1. 交换机确认

 继承RabbitTemplate.ConfirmCallback类重写以下方法
  @Override
    public void confirm(CorrelationData correlationData, boolean b, String s) {
        System.out.println("发送的消息"+correlationData);
        System.out.println("是否成功"+b);
        System.out.println("错误原因"+s);
        String id = correlationData.getId();
        }
    一般错误都是交换机名字错误
  1. 队列确认

 继承RabbitTemplate.ReturnCallback类重写以下方法
  @Override
    public void returnedMessage(Message message, int i, String s, String s1, String s2) {
        System.out.println("消息体"+message);
        System.out.println("应答码"+i);
        System.out.println("错误消息"+s);
        System.out.println("交换机"+s1);
        System.out.println("路由键"+s2);
        }
  一般错误都是路由键错误
 如果监听到消息 在使用时出现异常不算消费

延迟队列

发送消息给死信队列设置时间 时间一到给正常的交换价发信息

 //创建死信队列
 @Bean("dead")
    public Queue deadqueue(){
        Map map = new HashMap();
        map.put("x-dead-letter-exchange","normal-exchange");
        map.put("x-dead-letter-routing-key","normal");
        /**
          1、name: 队列的名称;
          2、durable: 是否持久化;
          3、exclusive: 是否独享、排外的;
          4、autoDelete: 是否自动删除;
          5.arguments:队列的其他属性参数,
          (1)x-message-ttl:消息的过期时间,单位:毫秒;
          (2)x-expires:队列过期时间,队列在多长时间未被访问将被删除,单位:毫秒;
          (3)x-max-length:队列最大长度,超过该最大值,则将从队列头部开始删除消息;
          (4)x-max-length-bytes:队列消息内容占用最大空间,受限于内存大小,超过该阈值则从队列头部开始删除消息;
          (5)x-overflow:设置队列溢出行为。这决定了当达到队列的最大长度时消息会发生什么。有效值是drop-head、reject-publish或reject-publish-dlx。仲裁队列类型仅支持drop-head;
          (6)x-dead-letter-exchange:死信交换器名称,过期或被删除(因队列长度超长或因空间超出阈值)的消息可指定发送到该交换器中;
          (7)x-dead-letter-routing-key:死信消息路由键,在消息发送到死信交换器时会使用该路由键,如果不设置,则使用消息的原来的路由键值
          (8)x-single-active-consumer:表示队列是否是单一活动消费者,true时,注册的消费组内只有一个消费者消费消息,其他被忽略,false时消息循环分发给所有消费者(默认false)
          (9)x-max-priority:队列要支持的最大优先级数;如果未设置,队列将不支持消息优先级;
          (10)x-queue-mode(Lazy mode):将队列设置为延迟模式,在磁盘上保留尽可能多的消息,以减少RAM的使用;如果未设置,队列将保留内存缓存以尽可能快地传递消息;
          (11)x-queue-master-locator:在集群模式下设置镜像队列的主节点信息。
          */
        return new Queue("dead",true,true,true,map);
    }
 
  @RequestMapping("/send/{msg}/{key}")
  //msg消息体key路由键
    public String test3(@PathVariable("msg")String msg,@PathVariable("key")String key){
  //唯一标识
        String uuid = UUID.randomUUID().toString();
        CorrelationData correlationData = new CorrelationData();
        correlationData.setId(uuid);
        //发给死信队列
        rabbitTemplate.convertAndSend("dead-exchange", key, msg, new MessagePostProcessor() {
        //设置时间
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setExpiration("10000");
                return message;
            }
        },correlationData);      
        return "ok";
 
    }

手动ACK

  1. 配置

 spring.rabbitmq.listener.simple.acknowledge-mode = manual
  1. 使用

 @RabbitHandler
 public void processMessage2(String message, Channel channel,@Headers Map<String,Object> map) {
    System.out.println(message);
    if (map.get("error")!= null){
        System.out.println("错误的消息");
        try {
            channel.basicNack((Long)map.get(AmqpHeaders.DELIVERY_TAG),false,true);     //否认消息
            return;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        channel.basicAck((Long)map.get(AmqpHeaders.DELIVERY_TAG),false);           //手动确认消息
    } catch (IOException e) {
        e.printStackTrace();
    }
 }
 
posted @   永远的幼稚  阅读(210)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示