消息中间件学习笔记(二)

交换机

1. 含义
  • Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!
  • 有交换机的消息发送模式
    • Publisher:生产者,不再发送消息到队列中,而是发给交换机
    • Exchange:交换机,一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。
    • Queue:消息队列也与以前一样,接收消息、缓存消息。不过队列一定要与交换机绑定。
    • Consumer:消费者,与以前一样,订阅队列,没有变化
2. 类型
(1)fanout交换机(FanoutExchange)
  • 作用:广播信息,即将消息交给所有绑定到交换机的队列(即每个队列都能收到交换机传来的消息)。

  • 我们最早在控制台使用的正是Fanout交换机

  • 代码

    • 在RabbitMQConfig中创建一个名为 fanout.exchange的交换机,类型是Fanout
        @Bean
        public FanoutExchange fanoutExchange(){
            return new FanoutExchange(env.getProperty("fanout.exchange"),true,false);
        }
        @Bean(name = "fanoutQueueOne")
        public Queue fanoutQueueOne(){
            return new Queue(env.getProperty("fanout.queue.one"),true);
        }
        @Bean(name = "fanoutQueueTwo")
        public Queue fanoutQueueTwo(){
            return new Queue(env.getProperty("fanout.queue.two"),true);
        }
      
      
    • 在RabbitMQConfig中创建两个队列fanout.queue1fanout.queue2,绑定到交换机fanout.exchange
        @Bean
        public Binding fanoutBindingOne(){
            return BindingBuilder.bind(fanoutQueueOne()).to(fanoutExchange());
        }
        @Bean
        public Binding fanoutBindingTwo(){
            return BindingBuilder.bind(fanoutQueueTwo()).to(fanoutExchange());
        }
      
    • 消息发送
      • 在FanoutPublisher中 添加方法sendMsg
            public void sendMsg(String msg){
            try{
            // 交换机名称
                String exchangeName = "fanout.exchange";
                // 消息
                String message = "hello, fanout!";
                rabbitTemplate.convertAndSend(exchangeName,message);
            }catch (Exception e){
                logger.error("Publisher error:", msg, e.fillInStackTrace());
            }
        }
        
      • 在测试类中添加测试:
            @Test
            public void testFanoutExchange() {
                fanoutPublisher.sendMsg("hello fanout");
            }
        
    • 消息接收
      在FanoutConsumer中添加两个方法,作为消费者:
        @RabbitListener(queues = "fanout.queue1")
        public void listenFanoutQueue1(String msg) {
            System.out.println("消费者1接收到Fanout消息:【" + msg + "】");
        }
    
        @RabbitListener(queues = "fanout.queue2")
        public void listenFanoutQueue2(String msg) {
            System.out.println("消费者2接收到Fanout消息:【" + msg + "】");
        }
    
  • 小结:Fanout交换机的作用是什么?

    • 接收publisher发送的消息
    • 将消息按照规则 路由到与之绑定的队列
    • 不能缓存消息,路由失败,消息丢失
    • FanoutExchange的会将消息路由到每个绑定的队列
(2)Direct交换机
  • 作用:直接传输消息,即将接收到的信息根据规则 路由到指定的Queue

  • 关键点

    • queue与Exchange设置一个BindingKey
    • publisher在向Exchange发送消息时,指定消息的 RoutingKey
    • Exchange将信息路由 到BindingKey与消息的 Routingkey一致的队列
  • 代码

    1. 声明一个名为direct.exchange的交换机
    2. 声明队列direct.queue1,绑定direct.exchangebindingKeykey.one
    3. 声明队列direct.queue2,绑定direct.exchangebindingKeykey.two
        @Bean
        public Binding DirectBindingOne(){
            return BindingBuilder.bind(directQueueOne()).
                    to(directExchange()).
                    with(env.getProperty("key.one"));
        }
        @Bean
        public Binding DirectBindingTwo(){
            return BindingBuilder.bind(directQueueTwo())
                    .to(directExchange()).
                    with(env.getProperty("key.two"));
        }
    
    1. 在DiectConsumer服务中,编写两个消费者方法,分别监听direct.queue1和direct.queue2
    2. 在DiectPublisher中编写sendMsg方法
      public void sendMsg(String msg){
          if(msg == null) return;
          try{
              //direct message
              rabbitTemplate.setExchange(env.getProperty("direct.exchange"));
              // 指定传给queue1
              rabbitTemplate.setRoutingKey(env.getProperty("key.two"));
              //message and send
              rabbitTemplate.convertAndSend(msg);
          }catch (Exception e){
              logger.error("Publisher error:", msg, e.fillInStackTrace());
          }
      }
      
    3. 在测试类中添加测试方法,向direct.exchange发送消息
  • 小结:Direct交换机与Fanout交换机的差异?

    • Fanout交换机将消息路由给每一个与之绑定的队列
    • Direct交换机根据RoutingKey判断路由给哪个队列
    • 如果多个队列具有相同的RoutingKey,则与Fanout功能类似
(3)Topic交换机
  • Topic:一种“发布-主题-订阅”模式的交换器。与Direct类似,只不过RoutingKey可以使用通配符
  • 路由支持通配符 “*” 和 “#”
    • *:匹配一个单词
    • #:匹配任意多个单词(包括0个)
    • 举例:
      • 例1
        1. item.#:能够匹配item.spu.insert 或者 item.spu
        2. item.*:只能匹配item.spu
      • 例2
        假如此时publisher发送的消息使用的RoutingKey共有四种:
        • china.news 代表有中国的新闻消息;
        • china.weather 代表中国的天气消息;
        • japan.news 则代表日本新闻
        • japan.weather 代表日本的天气消息;
          解释:
        • topic.queue1:绑定的是china.# ,凡是以 china.开头的routing key 都会被匹配到,包括:
        • china.news
        • china.weather
        • topic.queue2:绑定的是#.news ,凡是以 .news结尾的 routing key 都会被匹配。包括:
        • china.news
        • japan.news
  • 代码
    1. 声明一个名为topic.exchange的交换机
    2. 声明队列topic.queue1,绑定topic.exchangebindingKeykey.*.key
    3. 声明队列topic.queue2,绑定topic.exchangebindingKeykey.#.key
    4. 在TopicConsumer服务中,编写两个消费者方法,分别监听direct.queue1和direct.queue2
    5. 在TopicPublisher中编写sendMsg方法
    public void sendMsgTopic(String msg, String routingKey){
        try{
            rabbitTemplate.setExchange(env.getProperty("topic.exchange"));
            //set routing key
            rabbitTemplate.setRoutingKey(routingKey);
            Message message = MessageBuilder.withBody(msg.getBytes(StandardCharsets.UTF_8)).build();
            rabbitTemplate.convertAndSend(message);
            logger.info("TopicExchange producer, send:{} routing:{}", msg, routingKey);
        }catch (Exception e){
            logger.error("Publisher error:", msg, e.fillInStackTrace());
        }
    }
    
    1. 编写测试方法
  • 小结:描述下Direct交换机与Topic交换机的差异?
    • Topic交换机接收的消息RoutingKey必须是多个单词,以 **.** 分割
    • Topic交换机与队列绑定时的bindingKey可以指定通配符
      • #:代表0个或多个词
      • *:代表1个词
(4)Headers交换机
  • Headers:头匹配,基于MQ的消息头匹配,用的较少。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值