RabbitMQ学习系列(一)

RabbitMQ背景介绍

AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。
AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。

RabbitMQ是一个开源的AMQP实现,服务器端是用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
作为老牌的MQ消息队列,我打算在接下来的时间学习一下它。

RabbitMQ应用场景

消息队列的应用场景RabbitMQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取或者订阅队列中的消息。在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量。(随便看一下就可以了。知道怎么回事就行啦)

RabbitMQ环境安装

因为我是在Docker里面安装的,安装方法也比较简单。可以参考我之前的文章Docker下载和部署项目

在这里插入图片描述
RabbitMQ是带有客户端的消息中间件,我们可以通过网址来访问它(服务器IP:15672,一般默认密码都是 guest/guest)

在这里插入图片描述

RabbitMQ常用使用的开发方法

环境也安装好了 ,接下来我们在项目中实际操作一下,看看怎么使用的
先提一个概念

RabbitMQ有很多概念的名词;

Message
消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。

Publisher
消息的生产者,也是一个向交换器发布消息的客户端应用程序。

Exchange
交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。

Binding
绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。

Queue
消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。

Connection
网络连接,比如一个TCP连接。

Channel
信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内地虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。

Consumer
消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。

Virtual Host
虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。
Broker
表示消息队列服务器实体。

转载链接:https://www.jianshu.com/p/79ca08116d57/

由于这些内容设计的满多的内容,我打算在后续文章中分别介绍一下每一种的概念,这一次主要是介绍Exchange交换器和使用不同的Exchange交换器来做消息的接收和发送。

  1. DirectExchange

项目搭建

新建一个springboot项目,相关依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>RabbitMQDemo</groupId>
    <artifactId>RabbitMQDemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
</project>

在application中添加RabbitMQ的相关配置

server:
  port: 8888
  
spring:
  application:
    name: springboot-rabbitmq
  rabbitmq:
    host: /*这里替换成部署在Docker里面地址,如果部署在本地填写localhost即可*/
    port: 5672
    username: guest
    password: guest
    # 发布确认
    publisher-confirms: true
    virtual-host: /

交换器介绍

RabbitMQ常用的交换器一共有四种,基本上能满足所有的业务需求,交换机的实质其实是通过不同的队名名称进行匹配,接下来我们通过代码来介绍一个常用交换机的用法

  1. DirectExchange
    DirectExchange是RabbitMQ的默认交换机,直接使用routingKey匹配队列。通俗点描述就生产者直接把消息生产到指定到某一个队列上,消费者直接在这个队列上消费即可。
    **

新建一个队列

@Configuration
public class Rabbitonfig {

    /**
     *  配置routingKey,名字叫做hello的队列
     * @return
     */
    @Bean
    public Queue helloQueue() {
        return new Queue("hello");
    }
}

消息发送者

@Component
public class HelloSender {

//    rabbitTemplate是springboot 基于rabbitmq 实现的一些基本的队列消息发送功能。
    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send() {
        String context = "hello " + LocalDate.now();
        System.out.println("Sender : " + context);
        this.rabbitTemplate.convertAndSend("hello", context);
    }
}

消息接收者

/**
 * rabbit监听已经配置的列
 *
 * @author koala
 * @date 2018/11/17
 */

@Component
public class HelloReceiver {


    @RabbitHandler
    @RabbitListener(queues = "hello")
    public void process(String hello) {
        System.out.println("Receiver1  : " + hello);
    }

}

接着我们编写一个controller层给外部调用


    @GetMapping("/hello")
    public void hello(){
        helloSender.send();
    }

我们通过接口 http://localhost:8888/rabbit/hello 访问之后,消息生产者就会把接收到的消息发送给“hello”这个队列,而我们的消费者的监听hello队列就能处理这个消息。如下图
在这里插入图片描述

  1. TopicExchange
    TopicExchange是按规则转发消息,是交换机中最灵活的一个。也是最常用的一个。
    TopicExchange交换机支持使用通配符*、#
    *号只能向后多匹配一层路径。#号可以向后匹配多层路径。

首先我们定义2个队列:

/**
 * @author koala
 * @date 2018/11/17
 * RabbitTopicExchangeConfig
 * topic 是RabbitMQ中最灵活的一种方式,可以根据routing_key自由的绑定不同的队列
 */

@Configuration
public class RabbitTopicExchangeConfig {
	
	// 队列的名字
    final static String core = "api.core";	
    final static String payment = "api.payment";


	// 创建2个队列 api.core 和 api.payment
    @Bean
    public Queue coreQueue(){
        return new Queue(RabbitTopicExchangeConfig.core);
    }
    @Bean
    public Queue paymentQueue(){
        return new Queue(RabbitTopicExchangeConfig.payment);
    }

	/**
	* 分别创建TopicExchange交换器
	**/
    @Bean
    public TopicExchange coreExchange() {
        return new TopicExchange("coreExchange");
    }

    @Bean
    public TopicExchange paymentExchange() {
        return new TopicExchange("paymentExchange");
    }

    /**
     * 将两个队列分别部署到两个交换机上,并且设置 routingkey
     *  * 表示一次词,
     *  # 表示零个或者多个词
     */
    @Bean
    public Binding bindingCoreExchange(Queue coreQueue, TopicExchange coreExchange) {
        return BindingBuilder.bind(coreQueue).to(coreExchange).with("api.core.*");
    }

    @Bean
    public Binding bindingPaymentExchange(Queue paymentQueue, TopicExchange paymentExchange) {
        return BindingBuilder.bind(paymentQueue).to(paymentExchange).with("api.payment.#");
    }

这样我们的TopExchange对列就编写好了,接下来 我们编写一个发送端和一个接收端

TopicExchange发送端

/**
 * 添加两个消息发送类(生产者)
 *  添加一个user()方法,发送消息至coreExchange交换机且routingKey为api.core.user
 *  添加一个userQuery()方法,发送消息至coreExchange交换机且routingKey为api.core.user.query
 *
 * @author koala
 * @date 2018/11/17
 */
@Component
public class ApiCoreSender {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void user(String msg){
        System.out.println("api.core.user send message: "+msg);
        rabbitTemplate.convertAndSend("coreExchange", "api.core.user", msg);
    }

    public void userQuery(String msg){
        System.out.println("api.core.user.query send message: "+msg);
        rabbitTemplate.convertAndSend("coreExchange", "api.core.user.query", msg);
    }
}

TopicExchange接收端


/**
 * 监听routingKey为api.core的队列消息
 *
 * @author koala
 * @date 2018/11/17
 */
@Component
public class ApiCoreReceive {

        @RabbitHandler
        @RabbitListener(queues = "api.core")
        public void user(String msg) {
            System.out.println("ApiCoreReceive得到消息:"+ msg);
    }
}

接着我们编写一个controller 看一下效果

/**
 * TopicExchangeController层
 *
 * @author koala
 * @date 2019/1/16
 */

@RestController
@RequestMapping("/topic")
public class RabbitTopicExchangeController {

    private HelloSender helloSender;
    private ApiCoreSender apiCoreSender;

    @Autowired
    RabbitTopicExchangeController(HelloSender helloSender,ApiCoreSender apiCoreSender){
        this.helloSender = helloSender;
        this.apiCoreSender = apiCoreSender;
    }


    /**
     * 消息生产者
     * @param user
     */
    @GetMapping("/user")
    public void sendUser(@RequestParam String user) {
        this.apiCoreSender.user(user);
    }

    @GetMapping("/userQuery")
    public void sendUserQuert(@RequestParam String param){
        this.apiCoreSender.userQuery(param);
    }

执行:
http://localhost:8888//topic/user?user=koala
http://localhost:8888//topic/userQuery?param=koala-param

输出:
在这里插入图片描述

  • 为什么userQuery方法没有接收到消息呢?

这是因为 我们的我们TopicExchange绑定的队列是一个“api.core.”,在topicExchange中, 号只能向后匹配一层路径。而我们userQuery的发送端却是2层路径
在这里插入图片描述
在这里插入图片描述
所以我们的消息实际上并没有发送成功,所以接收端自然无法收到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值