RabbitMQ六大工作模式

交换机、队列、生产者消费者的关系

  • 消费者消费的核心API是channle.consumer(…),如果此时MQ中没有响应的队列就会报错
  • channle.queueDeclare() channle.exchangeDeclare() channle.queueBind()其实随便可以写在生产者or消费者,只需要保证在channle.consumer(…)之前即可
  • 删除exchange并不会导致绑定的queue删除,如果此时queue上有消息,删除exchange也不会导致消息丢失
  • 消费者只需要关心queue即可,不同的功能是由exchange的模式不同实现的

1.fanout扇出模式(发布订阅)

特点:

  • 声明exchange的时候指定为fanout,此时只需要绑定exchange和queue,至于routingKey是什么,设或者不设都不影响
  • 绑定后的queue都会收到该exchange发来的消息
  • 适合于:广播、订阅的场景

1.1生产者代码:

//fanout扇出 发布订阅
  public static void main(String[] args) throws Exception {
    Channel channel = getChannel();
    //1.在消费者启动之前,需要先声明  ——————交换机
    channel.exchangeDeclare("我的fanout交换机", BuiltinExchangeType.FANOUT);
    //2.在消费者启动之前,需要先声明  ——————队列
        //如果要绑定交换机,则第三个exclusive参数为false
    channel.queueDeclare("q1",true,false,false,null);
    channel.queueDeclare("q2",true,false,false,null);
    channel.queueDeclare("q3",true,false,false,null);
    //3.fanout交换机中任何对于routingKey的指定都没有效果
    channel.queueBind("q1","我的fanout交换机","随便写");
    channel.queueBind("q2","我的fanout交换机","11111");
    channel.queueBind("q3","我的fanout交换机","22222");
    /*
    * 其实exchange和queue的声明随便放在生产者or消费者
    * 但是一定要在消费者consumer之前声明,不然就会报错
    **/
    //4.开始发消息,producer发给指定的exchange,因为指定了fanout模式,
        //所以绑定该exchange的所有queue都会收到消息,且无关routingKey
    for(int i = 1 ; i < =10 ; i++){
      channel.basicPublish("我的fanout交换机"
                          ,"你看我随便指定routingKey"
                          , MessageProperties.PERSISTENT_TEXT_PLAIN
                          , ("第"+i+"条消息").getBytes(StandardCharsets.UTF_8));
      System.out.println("Producer发布消息:"+i);
    }

producer发布了10次给exchange,对应的3个队列,一共30条消息

1.2消费者代码

一共用3个消费者分别消费这三条队列的消息

代码示例:

  public static void main(String[] args) throws Exception {
    Channel channel = getChannel();

    DeliverCallback deliverCallback = (consumerTag,message)->{
      System.out.println("Consumer1收到消息:"+new String(message.getBody(),"UTF-8"));
    };
    channel.basicConsume("q1",true,
        deliverCallback,
        cancleCallBack -> {}//取消时什么都不做
        );

  }


2.direct路由模式

2.1默认交换机(AMQP default)

当生产者没有指定channle.exchangeDeclare(…)的模式时,默认使用的是直连交换机,routingKey就是queue名字
代码示例:

2.2路由模式

与默认的direct模式不同,路由模式需要显式的声明exchange,并绑定routingKey

2.2.1生产者

  public static void main(String[] args) throws Exception {

    Channel channel = getChannel();
    //1.声明为direct直连交换机
    channel.exchangeDeclare("logger", BuiltinExchangeType.DIRECT);

    channel.queueDeclare("ERROR",false,false,true,null);
       //INFO和WARNING级别的日志写入磁盘7天,ERROR级别的写入磁盘30天
    channel.queueDeclare("INFO_AND_WARNING",false,false,true,null);
    //2.绑定队列 交换机
    channel.queueBind("ERROR","logger","error_key");
    channel.queueBind("INFO_AND_WARNING","logger","info_warning_key");

    //3.模拟日志信息
    HashMap<String,String> map = new HashMap<>();
    map.put("INFO","INFO日志xxxxxxx");
    map.put("WARNING","WARNING警告yyyyyy");
    map.put("ERROR","ERROR错误zzzzzzz");

    map.forEach((key,value)->{

      try {
        if("ERROR".equals(key)){
          channel.basicPublish("logger","error_key",null,value.getBytes(StandardCharsets.UTF_8));
        }
        if("WARNING".equals(key) || "INFO".equals(key)){
          channel.basicPublish("logger","info_warning_key",null,value.getBytes(StandardCharsets.UTF_8));
        }
      } catch (IOException e) {
        e.printStackTrace();
      }

    });

  }

2.2.2消费者

一个处理ERROR日志的消费者:

  public static void main(String[] args) throws Exception{
    Channel channel = getChannel();

    channel.basicConsume("ERROR",true,(e1,e2)->{
      //把message写入磁盘30天
      System.out.println("ERROR日志写入磁盘:"+ new String(e2.getBody()));
    }, (e1,e2)->{});

  }

一个处理INFO和WARNING日志的消费者:

  public static void main(String[] args) throws Exception{

    Channel channel = getChannel();

    channel.basicConsume("INFO_AND_WARNING",true,
        (e1,e2)->{
          System.out.println(new String(e2.getBody()));
        },
        (e1,e2)->{});

  }


3.topic主题模式(通配符)

  • topic模式和direct模式相似,不过topic模式支持模糊匹配
  • 声明队列的时候不能用通配符,通配符是在queueBind的时候使用的
  • 其他的效果和direct一样,只不过是通配符的使用减少了direct的Bind次数

3.1示例

核心代码:

    //队列绑定交换机
    channel.queueBind(TOPIC_QUEUE_1,TOPIC_EXCHAGE,"item.#");
    channel.queueBind(TOPIC_QUEUE_2,TOPIC_EXCHAGE,"*.delete");

其他三种

一般只有画框的这三个用的多

1.简单模式

  • 不指定exchange
  • 一个producer
  • 一个consumer

2.工作模式

  • 不指定exchange
  • 一个producer
  • 多个consumer

3.RPC模式

期间遇到的Bug

在声明了交换机、队列之后,需要将队列与交换机绑定,但是我用的是channle.exchangeBind(destination,sourse,routingKey)这玩意其实是交换机之间互相绑定的,前两个参数都是exchange的名字
所以报错 channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'q1' in vhost '/', class-id=40, method-id=30)

改用chanle.queueBind即可

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值