第四十三章: 基于SpringBoot & RabbitMQ完成TopicExchange分布式消息消費(fèi)

我們?cè)谥暗膬蓚€(gè)章節(jié)第四十一章: 基于SpringBoot & RabbitMQ完成DirectExchange分布式消息消費(fèi)第四十二章: 基于SpringBoot & RabbitMQ完成DirectExchange分布式消息多消費(fèi)者消費(fèi)提高了RabbitMQ消息隊(duì)列的DirectExchange交換類型的消息消費(fèi)赊舶,我們之前的章節(jié)提到了RabbitMQ比較常用的交換類型有三種精耐,我們今天來(lái)看看TopicExchange主題交換類型粪摘。

免費(fèi)教程專題

恒宇少年在博客整理三套免費(fèi)學(xué)習(xí)教程專題魂莫,由于文章偏多特意添加了閱讀指南隅熙,新文章以及之前的文章都會(huì)在專題內(nèi)陸續(xù)填充沐旨,希望可以幫助大家解惑更多知識(shí)點(diǎn)衅金。

本章目標(biāo)

基于SpringBoot平臺(tái)完成RabbitMQTopicExchange消息類型交換噪伊。

SpringBoot 企業(yè)級(jí)核心技術(shù)學(xué)習(xí)專題


專題 專題名稱 專題描述
001 Spring Boot 核心技術(shù) 講解SpringBoot一些企業(yè)級(jí)層面的核心組件
002 Spring Boot 核心技術(shù)章節(jié)源碼 Spring Boot 核心技術(shù)簡(jiǎn)書每一篇文章碼云對(duì)應(yīng)源碼
003 Spring Cloud 核心技術(shù) 對(duì)Spring Cloud核心技術(shù)全面講解
004 Spring Cloud 核心技術(shù)章節(jié)源碼 Spring Cloud 核心技術(shù)簡(jiǎn)書每一篇文章對(duì)應(yīng)源碼
005 QueryDSL 核心技術(shù) 全面講解QueryDSL核心技術(shù)以及基于SpringBoot整合SpringDataJPA
006 SpringDataJPA 核心技術(shù) 全面講解SpringDataJPA核心技術(shù)
007 SpringBoot核心技術(shù)學(xué)習(xí)目錄 SpringBoot系統(tǒng)的學(xué)習(xí)目錄,敬請(qǐng)關(guān)注點(diǎn)贊5ā酥宴!!

解決問(wèn)題

之前少年也遇到了一個(gè)問(wèn)題,分類了多模塊后消息隊(duì)列無(wú)法自動(dòng)創(chuàng)建您觉,說(shuō)來(lái)也好笑拙寡,之前沒(méi)有時(shí)間去看這個(gè)問(wèn)題,今天在編寫本章文章時(shí)發(fā)現(xiàn)原因竟然是SpringBoot沒(méi)有掃描到common模塊內(nèi)的配置類琳水。讓我一陣的頭大~~~肆糕,我們?cè)?code>XxxApplication啟動(dòng)類上添加@ComponentScan(value = "com.hengyu.rabbitmq")就可以自動(dòng)創(chuàng)建隊(duì)列了0愣选!诚啃!

構(gòu)建項(xiàng)目

本章構(gòu)建項(xiàng)目時(shí)同樣采用多模塊的方式進(jìn)行設(shè)計(jì)淮摔,可以很好的看到消息處理的效果,因?yàn)槭嵌嗄K項(xiàng)目始赎,我們先來(lái)創(chuàng)建一個(gè)SpringBoot項(xiàng)目和橙,pom.xml配置文件依賴配置如下所示:

<dependencies>
        <!--rabbbitMQ相關(guān)依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <!--web相關(guān)依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--lombok依賴-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--spring boot tester-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--fast json依賴-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.40</version>
        </dependency>
    </dependencies>

下面我們先來(lái)構(gòu)建公共RabbitMQ模塊,因?yàn)槲覀兊南M(fèi)者以及生產(chǎn)者都是需要RabbitMQ相關(guān)的配置信息造垛,這里我們可以提取出來(lái)魔招,使用時(shí)進(jìn)行模塊之間的引用。

rabbitmq-topic-common

創(chuàng)建子模塊rabbitmq-topic-common五辽,在resources下添加application.yml配置文件并配置RabbitMQ相關(guān)的依賴配置办斑,如下所示:

spring:
  #rabbitmq消息隊(duì)列配置信息
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    publisher-confirms: true
定義交換配置信息

我們跟之前的章節(jié)一張,獨(dú)立編寫一個(gè)枚舉類型來(lái)配置消息隊(duì)列的交換信息杆逗,如下所示:

/**
 * rabbitmq交換配置枚舉
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/11/26
 * Time:13:56
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@Getter
public enum ExchangeEnum
{
    /**
     * 用戶注冊(cè)交換配置枚舉
     */
    USER_REGISTER_TOPIC_EXCHANGE("register.topic.exchange")
    ;
    private String name;

    ExchangeEnum(String name) {
        this.name = name;
    }
}
定義隊(duì)列配置信息

同樣消息隊(duì)列的基本信息配置也同樣采用枚舉的形式配置乡翅,如下所示:

/**
 * 隊(duì)列配置枚舉
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/11/26
 * Time:14:05
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@Getter
public enum QueueEnum
{
    /**
     * 用戶注冊(cè)
     * 創(chuàng)建賬戶消息隊(duì)列
     */
    USER_REGISTER_CREATE_ACCOUNT("register.account","register.#"),
    /**
     * 用戶注冊(cè)
     * 發(fā)送注冊(cè)成功郵件消息隊(duì)列
     */
    USER_REGISTER_SEND_MAIL("register.mail","register.#")
    ;
    /**
     * 隊(duì)列名稱
     */
    private String name;
    /**
     * 隊(duì)列路由鍵
     */
    private String routingKey;

    QueueEnum(String name, String routingKey) {
        this.name = name;
        this.routingKey = routingKey;
    }
}

消息隊(duì)列枚舉內(nèi)添加了兩個(gè)屬性,分別對(duì)應(yīng)了隊(duì)列名稱罪郊、隊(duì)列路由蠕蚜,我們本章所講解的TopicExchange類型消息隊(duì)列可以根據(jù)路徑信息配置多個(gè)消息消費(fèi)者,而轉(zhuǎn)發(fā)的匹配規(guī)則信息則是我們定義的隊(duì)列的路由信息悔橄。

定義發(fā)送消息路由信息

我們?cè)诎l(fā)送消息到隊(duì)列時(shí)靶累,需要我們傳遞一個(gè)路由相關(guān)的配置信息,RabbitMQ會(huì)根據(jù)發(fā)送時(shí)的消息路由規(guī)則信息與定義消息隊(duì)列時(shí)的路由信息進(jìn)行匹配橄维,如果可以匹配則調(diào)用該隊(duì)列的消費(fèi)者完成消息的消費(fèi)尺铣,發(fā)送消息路由信息配置如下所示:

/**
 * 消息隊(duì)列topic交換路由key配置枚舉
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/12/11
 * Time:21:58
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@Getter
public enum TopicEnum {
    /**
     * 用戶注冊(cè)topic路由key配置
     */
    USER_REGISTER("register.user")
    ;

    private String topicRouteKey;

    TopicEnum(String topicRouteKey) {
        this.topicRouteKey = topicRouteKey;
    }
}
路由特殊字符 #

我們?cè)?code>QueueEnum內(nèi)配置的路由鍵時(shí)有個(gè)特殊的符號(hào):#拴曲,在RabbitMQ消息隊(duì)列內(nèi)路由配置#時(shí)表示可以匹配零個(gè)或多個(gè)字符争舞,我們TopicEnum枚舉內(nèi)定義的register.user,則是可以匹配QueueEnum枚舉定義register.#隊(duì)列的路由規(guī)則澈灼。
當(dāng)然發(fā)送消息時(shí)如果路由傳遞:register.user.account也是可以同樣匹配register.#的路由規(guī)則竞川。

路由特殊字符 *

除此之外比較常用到的特殊字符還有一個(gè)*,在RabbitMQ消息隊(duì)列內(nèi)路由配置*時(shí)表示可以匹配一個(gè)字符叁熔,我們QueueEnum定義路由鍵如果修改成register.*時(shí)委乌,發(fā)送消息時(shí)路由為register.user則是可以接受到消息的。但如果發(fā)送時(shí)的路由為register.user.account時(shí)荣回,則是無(wú)法匹配該消息遭贸。

消息隊(duì)列配置

配置準(zhǔn)備工作已經(jīng)做好,接下來(lái)我們開(kāi)始配置隊(duì)列相關(guān)的內(nèi)容心软,跟之前一樣我們需要配置Queue壕吹、Exchange著蛙、Binding將消息隊(duì)列與交換綁定。下面我們來(lái)看看配置跟之前的章節(jié)有什么差異的地方耳贬,代碼如下所示:

/**
 * 用戶注冊(cè)消息隊(duì)列配置
 * ========================
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/11/26
 * Time:16:58
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@Configuration
public class UserRegisterQueueConfiguration {

    private Logger logger = LoggerFactory.getLogger(UserRegisterQueueConfiguration.class);
    /**
     * 配置用戶注冊(cè)主題交換
     * @return
     */
    @Bean
    public TopicExchange userTopicExchange()
    {
        TopicExchange topicExchange = new TopicExchange(ExchangeEnum.USER_REGISTER_TOPIC_EXCHANGE.getName());
        logger.info("用戶注冊(cè)交換實(shí)例化成功踏堡。");
        return topicExchange;
    }

    /**
     * 配置用戶注冊(cè)
     * 發(fā)送激活郵件消息隊(duì)列
     * 并設(shè)置持久化隊(duì)列
     * @return
     */
    @Bean
    public Queue sendRegisterMailQueue()
    {
        Queue queue = new Queue(QueueEnum.USER_REGISTER_SEND_MAIL.getName());
        logger.info("創(chuàng)建用戶注冊(cè)消息隊(duì)列成功");
        return queue;
    }

    /**
     * 配置用戶注冊(cè)
     * 創(chuàng)建賬戶消息隊(duì)列
     * 并設(shè)置持久化隊(duì)列
     * @return
     */
    @Bean
    public Queue createAccountQueue()
    {
        Queue queue = new Queue(QueueEnum.USER_REGISTER_CREATE_ACCOUNT.getName());
        logger.info("創(chuàng)建用戶注冊(cè)賬號(hào)隊(duì)列成功.");
        return queue;
    }

    /**
     * 綁定用戶發(fā)送注冊(cè)激活郵件隊(duì)列到用戶注冊(cè)主題交換配置
     * @return
     */
    @Bean
    public Binding sendMailBinding(TopicExchange userTopicExchange,Queue sendRegisterMailQueue)
    {
        Binding binding = BindingBuilder.bind(sendRegisterMailQueue).to(userTopicExchange).with(QueueEnum.USER_REGISTER_SEND_MAIL.getRoutingKey());
        logger.info("綁定發(fā)送郵件到注冊(cè)交換成功");
        return binding;
    }

    /**
     * 綁定用戶創(chuàng)建賬戶到用戶注冊(cè)主題交換配置
     * @return
     */
    @Bean
    public Binding createAccountBinding(TopicExchange userTopicExchange,Queue createAccountQueue)
    {
        Binding binding = BindingBuilder.bind(createAccountQueue).to(userTopicExchange).with(QueueEnum.USER_REGISTER_CREATE_ACCOUNT.getRoutingKey());
        logger.info("綁定創(chuàng)建賬號(hào)到注冊(cè)交換成功。");
        return binding;
    }
}

我們從上面開(kāi)始分析咒劲。
第一步: 首先我們創(chuàng)建了TopicExchange消息隊(duì)列對(duì)象顷蟆,使用ExchangeEnum枚舉內(nèi)的USER_REGISTER_TOPIC_EXCHANGE類型作為交換名稱。

第二步:我們創(chuàng)建了發(fā)送注冊(cè)郵件的隊(duì)列sendRegisterMailQueue腐魂,使用QueueEnum枚舉內(nèi)的類型USER_REGISTER_SEND_MAIL作為隊(duì)列名稱帐偎。

第三步:與發(fā)送郵件隊(duì)列一致,用戶創(chuàng)建完成后需要初始化賬戶信息挤渔,而createAccountQueue消息隊(duì)列后續(xù)邏輯就是來(lái)完成該工作肮街,使用QueueEnum枚舉內(nèi)的USER_REGISTER_CREATE_ACCOUNT枚舉作為創(chuàng)建賬戶隊(duì)列名稱。

第四步:在上面步驟中已經(jīng)將交換判导、隊(duì)列創(chuàng)建完成嫉父,下面就開(kāi)始將隊(duì)列綁定到用戶注冊(cè)交換,從而實(shí)現(xiàn)注冊(cè)用戶消息隊(duì)列消息消費(fèi)眼刃,sendMailBinding綁定了QueueEnum.USER_REGISTER_SEND_MAILRoutingKey配置信息绕辖。

createAccountBinding綁定了QueueEnum.USER_REGISTER_CREATE_ACCOUNTRoutingKey配置信息。

到目前為止我們完成了rabbitmq-topic-common模塊的所有配置信息擂红,下面我們開(kāi)始編寫用戶注冊(cè)消息消費(fèi)者模塊仪际。

rabbitmq-topic-consumer

我們首先來(lái)創(chuàng)建一個(gè)子模塊命名為rabbitmq-topic-consumer,在pom.xml配置文件內(nèi)添加rabbitmq-topic-common模塊的引用昵骤,如下所示:

....//
<dependencies>
        <!--公共模塊依賴-->
        <dependency>
            <groupId>com.hengyu</groupId>
            <artifactId>rabbitmq-topic-common</artifactId>
            <version>${parent.version}</version>
        </dependency>
    </dependencies>
....//
消費(fèi)者程序入口

下面我們來(lái)創(chuàng)建程序啟動(dòng)類RabbitMqTopicConsumerApplication树碱,在這里需要注意,手動(dòng)配置下掃描路徑@ComponentScan变秦,啟動(dòng)類代碼如下所示:

/**
 * 消息消費(fèi)者程序啟動(dòng)入口
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/12/11
 * Time:21:48
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@SpringBootApplication
@ComponentScan(value = "com.hengyu.rabbitmq")
public class RabbitMqTopicConsumerApplication {

    /**
     * logback
     */
    private static Logger logger = LoggerFactory.getLogger(RabbitMqTopicConsumerApplication.class);

    /**
     * 程序入口
     * @param args
     */
    public static void main(String[] args)
    {
        SpringApplication.run(RabbitMqTopicConsumerApplication.class,args);

        logger.info("【【【【【Topic隊(duì)列消息Consumer啟動(dòng)成功】】】】】");
    }
}

手動(dòng)配置掃描路徑在文章的開(kāi)始解釋過(guò)了成榜,主要目的是為了掃描到RabbitMQConfiguration配置類內(nèi)的信息,讓RabbitAdmin自動(dòng)創(chuàng)建配置信息到server端蹦玫。

發(fā)送郵件消費(fèi)者

發(fā)送郵件消息費(fèi)監(jiān)聽(tīng)register.mail消息隊(duì)列信息赎婚,如下所示:

/**
 * 發(fā)送用戶注冊(cè)成功郵件消費(fèi)者
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/12/11
 * Time:22:07
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@Component
@RabbitListener(queues = "register.mail")
public class SendMailConsumer
{

    /**
     * logback
     */
    Logger logger = LoggerFactory.getLogger(SendMailConsumer.class);

    /**
     * 處理消息
     * 發(fā)送用戶注冊(cè)成功郵件
     * @param userId 用戶編號(hào)
     */
    @RabbitHandler
    public void handler(String userId)
    {

        logger.info("用戶:{},注冊(cè)成功樱溉,自動(dòng)發(fā)送注冊(cè)成功郵件.",userId);

        //... 發(fā)送注冊(cè)成功郵件邏輯
    }
}

在這里我只是完成了消息的監(jiān)聽(tīng)挣输,具體的業(yè)務(wù)邏輯可以根據(jù)需求進(jìn)行處理。

創(chuàng)建賬戶消費(fèi)者

創(chuàng)建用戶賬戶信息消費(fèi)者監(jiān)聽(tīng)隊(duì)列register.account福贞,代碼如下所示:

/**
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/12/11
 * Time:22:04
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@Component
@RabbitListener(queues = "register.account")
public class CreateAccountConsumer {

    /**
     * logback
     */
    Logger logger = LoggerFactory.getLogger(CreateAccountConsumer.class);

    /**
     * 處理消息
     * 創(chuàng)建用戶賬戶
     * @param userId 用戶編號(hào)
     */
    @RabbitHandler
    public void handler(String userId)
    {
        logger.info("用戶:{}撩嚼,注冊(cè)成功,自動(dòng)創(chuàng)建賬戶信息.",userId);

        //... 創(chuàng)建賬戶邏輯
    }
}

創(chuàng)建賬戶,賬戶初始化邏輯都可以在handler方法進(jìn)行處理完丽,本章沒(méi)有做數(shù)據(jù)庫(kù)復(fù)雜的處理向瓷,所以沒(méi)有過(guò)多的邏輯處理在消費(fèi)者業(yè)務(wù)內(nèi)。

rabbitmq-topic-provider

接下來(lái)是我們的消息提供者的模塊編寫舰涌,我們依然先來(lái)創(chuàng)建程序入口類猖任,并添加掃描配置@ComponentScan路徑,代碼如下所示:

/**
 * 消息生產(chǎn)者程序啟動(dòng)入口
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/12/11
 * Time:21:48
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@SpringBootApplication
@ComponentScan(value = "com.hengyu.rabbitmq")
public class RabbitMqTopicProviderApplication {

    /**
     * logback
     */
    private static Logger logger = LoggerFactory.getLogger(RabbitMqTopicProviderApplication.class);

    /**
     * 程序入口
     * @param args
     */
    public static void main(String[] args)
    {
        SpringApplication.run(RabbitMqTopicProviderApplication.class,args);

        logger.info("【【【【【Topic隊(duì)列消息Provider啟動(dòng)成功】】】】】");
    }
}
定義消息發(fā)送接口

創(chuàng)建QueueMessageService隊(duì)列消息發(fā)送接口并添加send方法瓷耙,如下所示:

/**
 * 消息隊(duì)列業(yè)務(wù)
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/11/26
 * Time:14:50
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
public interface QueueMessageService
{
    /**
     * 發(fā)送消息到rabbitmq消息隊(duì)列
     * @param message 消息內(nèi)容
     * @param exchangeEnum 交換配置枚舉
     * @param routingKey 路由key
     * @throws Exception
     */
    public void send(Object message, ExchangeEnum exchangeEnum, String routingKey) throws Exception;
}

send方法內(nèi)有三個(gè)參數(shù)朱躺,解析如下:

  • message:發(fā)送消息內(nèi)容,可以為任意類型搁痛,當(dāng)然本章內(nèi)僅僅是java.lang.String长搀。
  • exchangeEnum:我們自定義的交換枚舉類型,方便發(fā)送消息到指定交換鸡典。
  • routingKey:發(fā)送消息時(shí)的路由鍵內(nèi)容源请,該值采用TopicEnum枚舉內(nèi)的topicRouteKey作為參數(shù)值。

下面我們來(lái)看看該接口的實(shí)現(xiàn)類QueueMessageServiceSupport內(nèi)send方法實(shí)現(xiàn)彻况,如下所示:

/**
 * 消息隊(duì)列業(yè)務(wù)邏輯實(shí)現(xiàn)
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/11/26
 * Time:14:52
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@Component
public class QueueMessageServiceSupport
    implements QueueMessageService
{
    /**
     * 消息隊(duì)列模板
     */
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public void send(Object message, ExchangeEnum exchangeEnum, String routingKey) throws Exception {
        //發(fā)送消息到消息隊(duì)列
        rabbitTemplate.convertAndSend(exchangeEnum.getName(),routingKey,message);
    }
}

我們通過(guò)RabbitTemplate實(shí)例的convertAndSend方法將對(duì)象類型轉(zhuǎn)換成JSON字符串后發(fā)送到消息隊(duì)列服務(wù)端谁尸,RabbitMQ接受到消息后根據(jù)注冊(cè)的消費(fèi)者并且路由規(guī)則篩選后進(jìn)行消息轉(zhuǎn)發(fā),并實(shí)現(xiàn)消息的消費(fèi)纽甘。

運(yùn)行測(cè)試

為了方便測(cè)試我們創(chuàng)建一個(gè)名為UserService的實(shí)現(xiàn)類良蛮,如下所示:

/**
 * 用戶業(yè)務(wù)邏輯
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/12/11
 * Time:22:10
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@Service
public class UserService
{
    /**
     * 消息隊(duì)列發(fā)送業(yè)務(wù)邏輯
     */
    @Autowired
    private QueueMessageService queueMessageService;

    /**
     * 隨機(jī)創(chuàng)建用戶
     * 隨機(jī)生成用戶uuid編號(hào),發(fā)送到消息隊(duì)列服務(wù)端
     * @return
     * @throws Exception
     */
    public String randomCreateUser() throws Exception
    {
        //用戶編號(hào)
        String userId = UUID.randomUUID().toString();
        //發(fā)送消息到rabbitmq服務(wù)端
        queueMessageService.send(userId, ExchangeEnum.USER_REGISTER_TOPIC_EXCHANGE, TopicEnum.USER_REGISTER.getTopicRouteKey());
        return userId;
    }
}

該類內(nèi)添加了一個(gè)名為randomCreateUser隨機(jī)創(chuàng)建用戶的方法悍赢,通過(guò)UUID隨機(jī)生成字符串作為用戶的編號(hào)進(jìn)行傳遞給用戶注冊(cè)消息隊(duì)列决瞳,完成用戶的模擬創(chuàng)建。

編寫測(cè)試用例

接下來(lái)我們創(chuàng)建RabbitMqTester測(cè)試類來(lái)完成隨機(jī)用戶創(chuàng)建消息發(fā)送左权,測(cè)試用例完成簡(jiǎn)單的UserService注入皮胡,并調(diào)用randomCreateUser方法,如下所示:

/**
 * ========================
 *
 * @author 恒宇少年
 * Created with IntelliJ IDEA.
 * Date:2017/12/11
 * Time:22:10
 * 碼云:http://git.oschina.net/jnyqy
 * ========================
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RabbitMqTopicProviderApplication.class)
public class RabbitMqTester
{
    /**
     * 用戶業(yè)務(wù)邏輯
     */
    @Autowired
   private UserService userService;

    /**
     * 模擬隨機(jī)創(chuàng)建用戶 & 發(fā)送消息到注冊(cè)用戶消息隊(duì)列
     * @throws Exception
     */
    @Test
    public void testTopicMessage() throws Exception
    {
        userService.randomCreateUser();
    }
}

到目前為止赏迟,我們的編碼已經(jīng)完成屡贺,下面我們按照下面的步驟啟動(dòng)測(cè)試:

  1. 啟動(dòng)rabbitmq-topic-consumer消息消費(fèi)者模塊,并查看控制臺(tái)輸出內(nèi)容是否正常
  2. 運(yùn)行rabbitmq-topic-provider模塊測(cè)試用例方法testTopicMessage
  3. 查看rabbitmq-topic-consumer控制臺(tái)輸出內(nèi)容

最終效果:


2017-12-30 18:39:16.819  INFO 2781 --- [           main] c.h.r.c.RabbitMqTopicConsumerApplication : 【【【【【Topic隊(duì)列消息Consumer啟動(dòng)成功】】】】】
2017-12-30 18:39:29.376  INFO 2781 --- [cTaskExecutor-1] c.h.r.consumer.CreateAccountConsumer     : 用戶:c6ef682d-da2e-4cac-a004-c244ff4c4503瀑梗,注冊(cè)成功烹笔,自動(dòng)創(chuàng)建賬戶信息.
2017-12-30 18:39:29.376  INFO 2781 --- [cTaskExecutor-1] c.h.rabbitmq.consumer.SendMailConsumer   : 用戶:c6ef682d-da2e-4cac-a004-c244ff4c4503裳扯,注冊(cè)成功抛丽,自動(dòng)發(fā)送注冊(cè)成功郵件.

總結(jié)

本章主要講解了TopicExchange交換類型如何消費(fèi)隊(duì)列消息,講解了常用到了的特殊字符#饰豺、*如何匹配亿鲜,解決了多模塊下的隊(duì)列配置信息無(wú)法自動(dòng)創(chuàng)建問(wèn)題。還有一點(diǎn)需要注意TopicExchange交換類型在消息消費(fèi)時(shí)不存在固定的先后順序!]锪饶套!

本章源碼已經(jīng)上傳到碼云:
SpringBoot配套源碼地址:https://gitee.com/hengboy/spring-boot-chapter
SpringCloud配套源碼地址:https://gitee.com/hengboy/spring-cloud-chapter

作者個(gè)人 博客
使用開(kāi)源框架 ApiBoot 助你成為Api接口服務(wù)架構(gòu)師

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市垒探,隨后出現(xiàn)的幾起案子妓蛮,更是在濱河造成了極大的恐慌,老刑警劉巖圾叼,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛤克,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡夷蚊,警方通過(guò)查閱死者的電腦和手機(jī)构挤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)惕鼓,“玉大人筋现,你說(shuō)我怎么就攤上這事∠淦纾” “怎么了矾飞?”我有些...
    開(kāi)封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)呀邢。 經(jīng)常有香客問(wèn)我凰慈,道長(zhǎng),這世上最難降的妖魔是什么驼鹅? 我笑而不...
    開(kāi)封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任微谓,我火速辦了婚禮,結(jié)果婚禮上输钩,老公的妹妹穿的比我還像新娘豺型。我一直安慰自己,他們只是感情好买乃,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布姻氨。 她就那樣靜靜地躺著,像睡著了一般剪验。 火紅的嫁衣襯著肌膚如雪肴焊。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天功戚,我揣著相機(jī)與錄音娶眷,去河邊找鬼。 笑死啸臀,一個(gè)胖子當(dāng)著我的面吹牛届宠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼豌注,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼伤塌!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起轧铁,我...
    開(kāi)封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤每聪,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后齿风,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體熊痴,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年聂宾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了果善。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡系谐,死狀恐怖巾陕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纪他,我是刑警寧澤鄙煤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站茶袒,受9級(jí)特大地震影響梯刚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜薪寓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一亡资、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧向叉,春花似錦锥腻、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至奇唤,卻和暖如春幸斥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咬扇。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工甲葬, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冗栗。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓演顾,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親隅居。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钠至,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容