• springboot集成rabbitmq


    概述

    主题交换机有fanout(扇形)、direct(直连)、topic(主题)三种。而主题交换机是可以通过配置包含前两种的,所以,本篇主要介绍主题交换机。

    topic路由器的关键在于定义路由键,定义routingKey名称不能超过255字节,使用“.”作为分隔符,例如:com.mq.rabbit.error。

    匹配规则

    匹配表达式可以用“*”和“#”匹配任何字符,具体规则如下:

    • “*”匹配一个分段(用“.”分割)的内容;
    • “#”匹配所有字符;

    例如发布了一个“cn.mq.rabbit.error”的消息:

    能匹配上的路由键:

    • cn.mq.rabbit.*
    • cn.mq.rabbit.#
    • #.error
    • cn.mq.#
    • #

    不能匹配上的路由键:

    • cn.mq.*
    • *.error
    • *

    交换机优点

    缓冲、分发

    虚拟主机

    每一个虚拟主机(vhost)相当于mini版的RabbitMQ服务器,拥有自己的队列,交换机和绑定,权限… 这使得一个RabbitMQ服务众多的应用程序,而不会互相冲突。

    rabbitMQ默认的虚拟主机为: “/” ,一般我们在创建Rabbit的用户时会再给用户分配一个虚拟主机

    适用场景

    有优先级的任务,根据任务的优先级把消息发送到对应的队列,这样可以指派更多的资源去处理高优先级的队列。消息需要基于多重条件进行路由到达对应队列,例如:日志系统,不仅可以根据日志的级别而且能根据日志的来源进行订阅。

    应用

    pom.xml

            <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>

    application.yml

    spring:
      application:
        name: rabbitmq-server
      rabbitmq:
        host: 127.0.0.1
        username: guest
        password: guest
        port: 5672
    
    server:
      port: 8080

    provider

    config

    package com.vast.rabbitmqprovider.config;
    
    import org.springframework.amqp.core.Binding;
    import org.springframework.amqp.core.BindingBuilder;
    import org.springframework.amqp.core.Queue;
    import org.springframework.amqp.core.TopicExchange;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class TopicRabbitConfig {
        //绑定键
        public final static String man = "topic.man";
        public final static String woman = "topic.woman";
    
        @Bean
        public Queue firstQueue() {
            return new Queue(TopicRabbitConfig.man);
        }
    
        @Bean
        public Queue secondQueue() {
            return new Queue(TopicRabbitConfig.woman);
        }
    
        @Bean
        TopicExchange exchange() {
            return new TopicExchange("topicExchange");
        }
    
    
        //将firstQueue和topicExchange绑定,而且绑定的键值为topic.man
        //这样只要是消息携带的路由键是topic.man,才会分发到该队列
        @Bean
        Binding bindingExchangeMessage() {
            return BindingBuilder.bind(firstQueue()).to(exchange()).with(man);
        }
    
        //将secondQueue和topicExchange绑定,而且绑定的键值为用上通配路由键规则topic.#
        // 这样只要是消息携带的路由键是以topic.开头,都会分发到该队列
        @Bean
        Binding bindingExchangeMessage2() {
            return BindingBuilder.bind(secondQueue()).to(exchange()).with("topic.#");
        }
    
    }

    controller

    package com.vast.rabbitmqprovider.controller;
    
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    
    @RestController
    public class TopicController {
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        @GetMapping("/sendTopicMessage1")
        public String sendTopicMessage1() {
            String messageId = String.valueOf(UUID.randomUUID());
            String messageData = "message: M A N ";
            String createTime = LocalDateTime.now().
                    format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            Map<String, Object> manMap = new HashMap<>();
            manMap.put("messageId", messageId);
            manMap.put("messageData", messageData);
            manMap.put("createTime", createTime);
            rabbitTemplate.convertAndSend("topicExchange", "topic.man", manMap);
            return "ok";
        }
    
        @GetMapping("/sendTopicMessage2")
        public String sendTopicMessage2() {
            String messageId = String.valueOf(UUID.randomUUID());
            String messageData = "message: woman is all ";
            String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            Map<String, Object> womanMap = new HashMap<>();
            womanMap.put("messageId", messageId);
            womanMap.put("messageData", messageData);
            womanMap.put("createTime", createTime);
            rabbitTemplate.convertAndSend("topicExchange", "topic.woman", womanMap);
            return "ok";
        }
    }

    consumer

    config

    package com.vast.rabbitmqconsumer.config;
    
    import org.springframework.amqp.core.Binding;
    import org.springframework.amqp.core.BindingBuilder;
    import org.springframework.amqp.core.Queue;
    import org.springframework.amqp.core.TopicExchange;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @Author : ydd
     * @CreateTime : 2019/12/17
     * @Description :
     **/
    
    @Configuration
    public class TopicRabbitConfig {
        //绑定键
        public final static String man = "topic.man";
        public final static String woman = "topic.woman";
    
        @Bean
        public Queue firstQueue() {
            return new Queue(TopicRabbitConfig.man);
        }
    
        @Bean
        public Queue secondQueue() {
            return new Queue(TopicRabbitConfig.woman);
        }
    
        @Bean
        TopicExchange exchange() {
            return new TopicExchange("topicExchange");
        }
    
    
        //将firstQueue和topicExchange绑定,而且绑定的键值为topic.man
        //这样只要是消息携带的路由键是topic.man,才会分发到该队列
        @Bean
        Binding bindingExchangeMessage() {
            return BindingBuilder.bind(firstQueue()).to(exchange()).with(man);
        }
    
        //将secondQueue和topicExchange绑定,而且绑定的键值为用上通配路由键规则topic.#
        // 这样只要是消息携带的路由键是以topic.开头,都会分发到该队列
        @Bean
        Binding bindingExchangeMessage2() {
            return BindingBuilder.bind(secondQueue()).to(exchange()).with("topic.#");
        }
    
    }
    package com.vast.rabbitmqconsumer.config;
    
    import com.vast.rabbitmqconsumer.receiver.TopicManReceiver;
    import org.springframework.amqp.core.AcknowledgeMode;
    import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
    import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @Author : ydd
     * @CreateTime : 22019/12/17
     * @Description :
     **/
    @Configuration
    public class MessageListenerConfig {
    
        @Autowired
        private CachingConnectionFactory connectionFactory;
        @Autowired
        private TopicManReceiver topicManReceiver;//Topic消息接收处理类
        @Autowired
        TopicRabbitConfig topicRabbitConfig;
        @Bean
        public SimpleMessageListenerContainer simpleMessageListenerContainer() {
            SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
            container.setConcurrentConsumers(1);
            container.setMaxConcurrentConsumers(1);
            container.setAcknowledgeMode(AcknowledgeMode.MANUAL); // RabbitMQ默认是自动确认,这里改为手动确认消息
            container.setQueues(topicRabbitConfig.firstQueue());
            container.setMessageListener(topicManReceiver);
            return container;
        }
    }

    receiver

    package com.vast.rabbitmqconsumer.receiver;
    
    import com.rabbitmq.client.Channel;
    import org.springframework.amqp.core.Message;
    import org.springframework.amqp.rabbit.annotation.RabbitHandler;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
    import org.springframework.stereotype.Component;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Author : ydd
     * @CreateTime : 2019/12/17
     * @Description :
     **/
    @Component
    @RabbitListener(queues = "topic.man")
    public class TopicManReceiver implements ChannelAwareMessageListener {
    
    //    @RabbitHandler
    //    public void process(Map testMessage) {
    //        System.out.println("TopicManReceiver消费者收到消息  : " + testMessage.toString());
    //    }
    
        @Override
        public void onMessage(Message message, Channel channel) throws Exception {
            long deliveryTag = message.getMessageProperties().getDeliveryTag();
            try {
                //因为传递消息的时候用的map传递,所以将Map从Message内取出需要做些处理
                String msg = message.toString();
                String[] msgArray = msg.split("'");//可以点进Message里面看源码,单引号直接的数据就是我们的map消息数据
                Map<String, String> msgMap = mapStringToMap(msgArray[1].trim());
                String messageId=msgMap.get("messageId");
                String messageData=msgMap.get("messageData");
                String createTime=msgMap.get("createTime");
                System.out.println("messageId:"+messageId+"  messageData:"+messageData+"  createTime:"+createTime);
    //            channel.basicAck(deliveryTag, true);
                channel.basicReject(deliveryTag, true);//为true会重新放回队列
            } catch (Exception e) {
                channel.basicReject(deliveryTag, false);
                e.printStackTrace();
            }
        }
    
        //{key=value,key=value,key=value} 格式转换成map
        private Map<String, String> mapStringToMap(String str) {
            str = str.substring(1, str.length() - 1);
            String[] strs = str.split(",");
            Map<String, String> map = new HashMap<String, String>();
            for (String string : strs) {
                String key = string.split("=")[0].trim();
                String value = string.split("=")[1];
                map.put(key, value);
            }
            return map;
        }
    }
    package com.vast.rabbitmqconsumer.receiver;
    
    import org.springframework.amqp.rabbit.annotation.RabbitHandler;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;
    
    import java.util.Map;
    
    /**
     * @Author : ydd
     * @CreateTime : 2019/12/17
     * @Description :
     **/
    
    @Component
    @RabbitListener(queues = "topic.woman")
    public class TopicTotalReceiver {
    
        @RabbitHandler
        public void process(Map testMessage) {
            System.out.println("TopicTotalReceiver消费者收到消息  : " + testMessage.toString());
        }
    }
  • 相关阅读:
    系统架构师学习笔记_第十一章(下)
    通过IronRuby和C#学习RUBY系列[0]
    TIPS to comment your code
    超级简单:DIV布局
    js 查询XML数据添加到HTML select控件
    《架构之美》读书笔记(一)
    18个不常见的C#关键字,您使用过几个?
    如何成为人尽皆知的C#开发人员
    实现Visual Studio 2010一个很简单的很酷的扩展
    一种简单的直观的高效的权限设计
  • 原文地址:https://www.cnblogs.com/yanduanduan/p/12055061.html
Copyright © 2020-2023  润新知