Spring Boot(十):整合RabbitMQ消息中间件

RabbitMQ背景

消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,高可用,可伸缩和最终一致性。

消息中间件的分类

①、ActiveMQ:是Apache软件基金会所研发的开放源代码消息中间件;由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。
②、RabbitMQ:是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。
③、Kafka:是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。
④、RocketMQ:是阿里巴巴集团自主研发的专业消息中间件。

上面每个消息中间件的解释大部分来自百度百科。

RabbitMQ的特点

1、可靠性:使用一些机制来保证可靠性,如持久化、传输确认、发布确认。
2、消息集群:多个RabbitMQ服务器可以组成一个集群,形成一个逻辑Broker(缓存代理)。
3、高可用:队列可以在集群中的机器上进行镜像,使得在部分节点出问题的情况下队列仍然可用。
4、多种协议:RabbitMQ支持多种消息队列协议,比如STOMP、MQTT等。
5、多语言客户端:RabbitMQ几乎支持所有常用语言,比如Java、.NET、Ruby等。
6、管理界面:RabbitMQ提供了一个易用的用户界面,使得用户可以监控和管理消息Broker的许多方面。
7、插件机制:RabbitMQ提供了许多插件,来从多方面进行扩展,也可以编写自己的插件。
8、跟踪机制:如果消息异常,RabbitMQ提供了消息跟踪机制。

RabbitMQ架构图的介绍

图片引用于百度
ps: 图片来源于网络

根据这张架构图,可以对RabbitMQ中各个组件进行介绍:

RabbitMQ Server:也叫Broker Server,它是一种传输服务。 它的角色就是维护一条从Producer到Consumer的路线,保证数据能够按照指定的方式进行传输。

Producer:消息生产者,消息生产者连接RabbitMQ服务器然后将消息投递到Exchange。

Consumer:消息消费者,消息消费者订阅队列,RabbitMQ将Queue中的消息发送到消息消费者。

Exchange:生产者将消息发送到Exchange(交换器),由Exchange将消息路由到一个或多个Queue中(或者丢弃)。Exchange并不存储消息。RabbitMQ中的Exchange有direct、fanout、topic、headers四种类型,每种类型对应不同的路由规则。

Queue:(队列)是RabbitMQ的内部对象,用于存储消息。消息消费者就是通过订阅队列来获取消息的,RabbitMQ中的消息都只能存储在Queue中,生产者生产消息并最终投递到Queue中,消费者可以从Queue中获取消息并消费。多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。

RoutingKey:生产者在将消息发送给Exchange的时候,一般会指定一个Routing key,来指定这个消息的路由规则,而这个Routing key需要与Exchange Type及Binding key联合使用才能最终生效。在Exchange Type与Binding key固定的情况下(在正常使用时一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时,通过指定Routing key来决定消息流向哪里。RabbitMQ为Routing key设定的长度限制为255bytes。

Connection:(连接):Producer和Consumer都是通过TCP连接到RabbitMQ Server的。程序的起始处就是建立这个TCP连接。

Channels:(信道):它建立在上述的TCP连接中。数据流动都是在Channel中进行的。也就是说,一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。

VirtualHost:权限控制的基本单位,一个VirtualHost里面有若干Exchange和MessageQueue,以及指定被哪些user使用。

RabbitMQ的安装

至于RabbitMQ的安装,这里就不做说明了,网上也有很多安装教程,各位读者可以根据相关资料进行安装。博主这里使用的是本地Windows上安装的RabbitMQ。安装完成,通过命令安装管理界面:

rabbitmq‐plugins enable rabbitmq_management

然后输入地址:http://127.0.0.1:15672,就能看到如下界面。

用户名和密码默认为: guest

三种模式的讲解与代码实现

RabbitMQ有三种模式:直接模式(Direct)、分列模式(Fanout)、主题模式(Topic)。

直接模式(Direct)

将消息发给唯一一个节点时使用这种模式。任何发送到Direct Exchange的消息都会被转发到RouteKey中指定的Queue。

特点
1、可以使用RabbitMQ自带的Exchange " " (该Exchange的名字为空字符串);
2、这种模式下不需要将Exchange进行任何绑定操作;
3、消息传递时需要一个"RouteKey",可以理解为要发送到的队列名;
4、如果vhost中不存在RouteKey中指定的队列名,则该消息会被抛弃。

代码实现
这里使用的是SpringBoot,需要引入RabbitMQ的pom依赖。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

然后增加RabbitMQ的配置。

spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest

配置完成,先创建消息的生产者,这里使用SpringBoot中提供的测试类。

@RunWith(SpringRunner.class)
@SpringBootTest
public class MonitorApplicationTests {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void direct(){
        rabbitTemplate.convertAndSend("qfcwx","direct模式");
    }
}

注意,这里一定要先通过RabbitMQ的管控台创建好名为"qfcwx"的队列。不然启动会报错的。

然后启动测试类,再通过管控台查看当前消息队列中是否存在消息。

可以看到,此时队列中确实是有一条消息等待消费。

然后创建消息的消费者。

@Component
@RabbitListener(queues = "qfcwx")
public class DirectListener {

    @RabbitHandler
    private void direct(String message){
        System.out.println("direct模式下收到的消息:" + message);
    }
}

@RabbitListener:标注在类上面的时候,需要配合@RabbitHandler注解一起使用,queues指明监听哪个队列。

运行启动类,通过控制台看输出结果。

查看管控台发现,队列中的消息也被消费了。

分列模式(Fanout)

将消息一次发给多个队列时,需要使用这种模式。任何发送到Fanout Exchange的消息都会被转发到与该Exchange绑定的所有Queue上。

特点
1、这种模式不需要RouteKey。
2、这种模式需要提前将Exchange与Queue进行绑定,一个Exchange可以绑定多个Queue,一个Queue可以同多个Exchange进行绑定。
3、如果接受到消息的Exchange没有与任何Queue绑定,则消息会被丢弃。

代码实现
这次首先通过管控台创建Exchange与Queue。这里创建名为"qfcwx_exchange"的交换器,然后创建名为"qfcwx_a"、"qfcwx_b"的两个队列。然后将两个队列绑定到交换器上。

接着通过代码编写生产者:

    @Test
    public void fanout(){
        rabbitTemplate.convertAndSend("qfcwx_exchange","","fanout模式");
    }

然后创建消费者:

@Component
public class FanoutListener {

    @RabbitListener(queues = "qfcwx_a")
    public void fanoutToQueueOne(String message) {
        System.out.println("队列[qfcwx_a],收到了交换机[qfcwx_exchange]的消息:" + message);
    }

    @RabbitListener(queues = "qfcwx_b")
    public void fanoutToQueueTwo(String message) {
        System.out.println("队列[qfcwx_b],收到了交换机[qfcwx_exchange]的消息:" + message);
    }
}

直接启动测试类,通过控制台查看结果。

主题模式(Topic)

任何发送到Topic Exchange的消息都会被转发到所有关心RouteKey中指定话题的Queue上,交换器是一个名称与队列绑定的列表。当消息发布到交换器时,实际上是由你所连接的信道,将消息路由键同交换器上绑定的列表进行比较,最后路由消息。

看到这里,相信很多读者会一脸懵逼,下面用表格展示一下。

routing key binding key
qfcwx.mobile qfcwx.#
test.mail test.#

表格只是大致说明这是一种匹配的规则。符号 # 匹配一个或多个词,符号 * 匹配不多不少一个词。这里也许博主说的比较模糊了。等会通过代码来讲解吧。

特点
1、每个队列都有其关心的主题,所有的消息都带有一个"标题"(RouteKey),Exchange会将消息转发到所有关注主题能与RouteKey模糊匹配的队列。
2、这种模式需要RouteKey,也需要绑定Exchange与Queue。
3、在进行绑定时,要提供一个该队列关心的主题,如"#.log.#“表示该队列关心所有涉及log的消息。
4、”#“表示0个或若干个关键字,”"表示一个关键字。如"log."能与"log.warn"匹配,无法与"log.warn.timeout"匹配;但是"log.#"能与上述两者匹配。
5、如果Exchange没有发现能够与RouteKey匹配的Queue,则会抛弃此消息。

代码实现

还是先操作管控台,创建一个交换机,命名为log_exchange。

然后,分别创建交互机下队列与routing的匹配规则。


接着创建生产者:

    @Test
    public void topic() {
        rabbitTemplate.convertAndSend("log_exchange", "log.error", "topic模式");
        rabbitTemplate.convertAndSend("log_exchange", "debug.log", "topic模式");
        rabbitTemplate.convertAndSend("log_exchange", "info.log", "topic模式");
    }

这里指定了交换机的名称和routingkey。

创建消费者。

@Component
public class TopicListener {

    @RabbitListener(queues = "qfcwx_a")
    public void topicToQueueOne(String message) {
        System.out.println("队列[qfcwx_a],收到了交换机[log_exchange]的消息:" + message);
    }

    @RabbitListener(queues = "qfcwx_b")
    public void topicToQueueTwo(String message) {
        System.out.println("队列[qfcwx_b],收到了交换机[log_exchange]的消息:" + message);
    }

    @RabbitListener(queues = "qfcwx_c")
    public void topicToQueueThree(String message) {
        System.out.println("队列[qfcwx_c],收到了交换机[log_exchange]的消息:" + message);
    }
}

启动程序,看控制太打印的结果。

因为上面生产者的routingkey与我们先前在管控台配置的"qfcwx_c"队列的routingkey不匹配,所以,队列"qfcwx_c"并没有收到消息。这就是主题模式的使用方法。

到这里,关于RabbitMQ与SpringBoot整合的内容就讲完了。全文其实大部分都在讲解RabbitMQ的知识,特别是三种模式,一、二种模式好理解,第三种还需要结合代码来理解。如果文中存在什么问题或者错误的地方,也希望各位读者提出。

人都有以第一印象定好坏的习惯,以为一个人好时,就会爱屋及乌,以为一个人不好时,就会全盘否认。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章