消息队列 (RabbitMQ基础)

消息队列需求场景

与服务之间的通信方式有两种:同步调用 和 异步消息调用
同步调用:远程过程调用,REST和RPC
异步消息调用:消息队列在这里插入图片描述

消息队列概念

MQ全称为Message Queue,消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。
消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。
在这里插入图片描述
RabbitMQ 稳定可靠,数据一致,支持多协议,有消息确认,基于erlang语言
Kafka 高吞吐,高性能,快速持久化,无消息确认,无消息遗漏,可能会有有重复消息,依赖于zookeeper,成本高.
ActiveMQ 不够灵活轻巧,对队列较多情况支持不好.
RocketMQ 性能好,高吞吐,高可用性,支持大规模分布式,协议支持单一

搭建RabbitMQ

创建用户

在这里插入图片描述

创建虚拟主机

在这里插入图片描述

在这里插入图片描述

创建Maven项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

添加依赖

  <dependencies>
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>4.5.0</version>
        </dependency>
 </dependencies>

简单模式

在这里插入图片描述

入门工程-生产者

在这里插入图片描述

// 1.创建连接工厂(设置RabbitMQ的连接参数)
//2.创建连接
//3.创建频道
//4.声明队列
//5.发送消息
//6.关闭资源

package com.itheima.rabbitmq.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
//简单模式:发送消息
public class Producer {
    static final String QUEUE_NAME = "simple";
    public static void main(String[] args) throws IOException, TimeoutException {
       // 1.创建连接工厂(设置RabbitMQ的连接参数)
        ConnectionFactory connectionFactory =new ConnectionFactory();
        //主机地址;默认为 localhost
        connectionFactory.setHost("47.103.193.112");
        //连接端口;默认为 5672
        connectionFactory.setPort(5672);
        //虚拟主机名称;默认为 /
       connectionFactory.setVirtualHost("/jiajia");
        //连接用户名;默认为guest
        connectionFactory.setUsername("jiajia");
        //连接密码;默认为guest
        connectionFactory.setPassword("123456");
        //2.创建连接
        Connection connection = connectionFactory.newConnection();
        //3.创建频道
        Channel channel = connection.createChannel();
        //4.声明队列
        /**
         * 参数1:队列名称
         * 参数2:是否定义持久化队列(消息会持久保存在服务器)
         * 参数3:是否独占本次连接
         * 参数4:是否在不使用的时候自动删除队列
         * 参数5:队列其它参数
         */
        channel.queueDeclare(QUEUE_NAME,true,false,false,null);
        //5.发送消息
        String message = "hello world";
        /**
         * 参数1:交换机名称,如果没有指定则使用默认Default Exchage
         * 参数2:路由key,简单模式可以传递队列名称
         * 参数3:消息其它属性
         * 参数4:消息内容
         */
        channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
        System.out.println("已发消息:"+message);
        //6.关闭资源
        channel.close();
        connection.close();
    }
}

入门工程-消费者

    //1.创建连接工厂
    //2.创建连接
    //3.创建频道
    //4.声明(创建)队列
    //5.创建消费者;并设置消息处理
    //6.监听消息
package com.itheima.rabbitmq.simple;
import com.itheima.rabbitmq.util.ConnectionUtil;
import com.rabbitmq.client.*;
import java.io.IOException;
public class Consumer {
    public static void main(String[] args) throws Exception {
        //1.创建连接工厂
        //2.创建连接
       Connection connection =  ConnectionUtil.getConnection();
        //3.创建频道
        Channel channel = connection.createChannel();
        //4.声明(创建)队列
        channel.queueDeclare(Producer.QUEUE_NAME,true,false,false,null);
        //5.创建消费者;并设置消息处理
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                //路由key
                System.out.println("路由key为:" + envelope.getRoutingKey());
                //交换机
                System.out.println("交换机为:" + envelope.getExchange());
                //消息id
                System.out.println("消息id为:" + envelope.getDeliveryTag());
                //收到的消息
                System.out.println("接收到的消息为:" + new String(body, "utf-8"));
              }
            };
        //6.监听消息
            /**
             * 参数1:队列名称
             * 参数2:是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手动确认
             * 参数3:消息接收到后回调
             */
            channel.basicConsume(Producer.QUEUE_NAME,true,defaultConsumer);
            //不关闭资源,应该一直监听消息
            //channel.close();
            //connection.close();
    }
}

//ConnectionUtil.java
package com.itheima.rabbitmq.util;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ConnectionUtil {
    public static Connection getConnection() throws IOException, TimeoutException {
        // 1.创建连接工厂(设置RabbitMQ的连接参数)
        ConnectionFactory connectionFactory =new ConnectionFactory();
        //主机地址;默认为 localhost
        connectionFactory.setHost("47.103.193.112");
        //连接端口;默认为 5672
        connectionFactory.setPort(5672);
        //虚拟主机名称;默认为 /
        connectionFactory.setVirtualHost("/jiajia");
        //连接用户名;默认为guest
        connectionFactory.setUsername("jiajia");
        //连接密码;默认为guest
        connectionFactory.setPassword("123456");
        //2.创建连接
        return connectionFactory.newConnection();
    }
}

入门工程测试

运行Producer.java
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行Consumer.java
在这里插入图片描述
此时:
在这里插入图片描述

Work queues工作队列模式

在这里插入图片描述

在同一个队列中有多个消费者,竞争关系
生产者:发30个消息
消费者:两个消费者监听同一个消息队列,查看两个消费者接收消息是否重复。

//Producer.java
//5.发送消息
        for (int i = 0; i <= 30 ; i++) {
            String message = "hello world,work模式" + i;
            channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
            System.out.println("已发消息: "+message);
        }

Consumer1.java

在这里插入图片描述

Consumer2.java (同Consumer1.java)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结论:一个消息只能被一个消费者接收,其他消费者不能接收到同一条消息
应用场景:消费者处理任务比较耗时时,添加同一个队列的消费者来提高任务处理能力。

订阅模式

在这里插入图片描述

比前两种多了Exchange交换机,接收生产者发送的消息并决定如何投递消息到其绑定的队列。消息的投递取决于交换机的类型。
交换机类型:广播(fanout),定向(direct),通配符(topic)
交换机只做消息转发,自身不存储数据。

生产者(发送10个消息):
1.创建连接
2.创建频道
3.声明交换机
4.声明队列
5.队列绑定到交换机
6.发送消息
7.关闭资源
消费者(至少两个)

  1. 创建连接
  2. 创建频道
  3. 声明交换机
  4. 声明队列
  5. 队列绑定到交换机
  6. 创建消费者
  7. 监听队列
    在这里插入图片描述
    在这里插入图片描述
    Consumer2.java
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    结论:一个消息可以被多个消费者接收;一个消费者对应的队列,该队列只能被一个消费者监听。使用了订阅模式中的交换机类型为:广播。

路由模式

在这里插入图片描述
生产者:发送两条消息(路由key分别为:insert,update)
消费者:创建两个消费者,监听的队列分别绑定路由key为:insert,update
1.消息中路由key为insert 的,会被绑定路由为insert的队列接收,并被其监听的消费者接收、处理
2.消息中路由key为update的,会被绑定路由为update的队列接收,并被其监听的消费者接收、处理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结论:Routing模式要求队列绑定到交换机的时候指定路由key;消费发送时候需要携带路由key;只有消息的路由key与队列的路由key完全一致,才能让该队列接收到消息。

通配符模式

在这里插入图片描述
绑定 rouer key时可以使用通配符
#:匹配1个或多个
*:匹配不多不少恰好一个
生产者:发送包含有 item.insert 、item.update 、 item.delete的3种路由key消息
消费者1:监听的队列绑定的交换机类型为 item.insert 、item.delete
消费者1:监听的队列绑定的交换机类型为 item.*
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结论:可以根据路由key将信息传递到对应的路由key的队列;队列绑定到交换机的路由key可以有多个;通配符模式中路由key可以使用*#;使用了通配符模式后对应路由key配置更灵活。

RabbitMQ模式总结

不直接Exchange交换机(默认交换机)
1.simple简单模式:一个生产者生产一个消息,到一个队列,被一个消费者接收
2.work工作队列模式:生产者发送消息到一个队列中,然后可以被多个消费者监听该队列; -一个消息只能被一个消费者接收,消费者之间是竞争关系

使用Exchange交换机;订阅模式(交换机:广播fanout、 定向direct、 通配符topic )
1.发布与订阅模式:使用了fanout广播类型的交换机,可以将一个消息发送到所有绑定了该交换机的队列
2. 路由模式:使用了direct定向类型的交换机,消费会携带路由key ,交换机根据消息的路由key与队列的路由key进行对比,一致的话那么该队列可以接收到消息
3.通配符模式:使用了topic通配符类型的交换机,消费会携带路由key(*, #) , 交换机根据消息的路由key与队列的路由key进行对比,匹配的话那么该队列可以接收到消息

整合springboot

springboot提供了AMQP的整合;可以使用RabbitTemplate发送消息,使用**@RabbitListener**接收消息。
生产者工程:spring-boot-rabbitmq-producer:发送消息
消费者工程:spring-boot-rabbitmq-customer:接收消息

file new moudle maven
在这里插入图片描述
在这里插入图片描述

<!--  pom.xml(producer)-->
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
 </parent>
 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
  </dependencies>
<!--  pom.xml(customer)-->
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
 </parent>
 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
  </dependencies>

启动引导类,配置文件yml
在这里插入图片描述

配置生产者工程

使用通配符模式
1.配置RabbitMQ的连接参数:主机、连接端口、虚拟主机、用户名、密码
2.声明交换机、队列并将队列绑定到交换机,指定的路由key

spring:
  rabbitmq:
    host: 47.103.193.112
    post: 5672
    virtual-host: /jiajia
    username: jiajia
    password: 123456
@Configuration
public class RabbitMQConfig {
    //声明交换机
    public static final String ITEM_TOPIC_EXCHANGE = "item_topic_exchange";
    //声明队列
    public static final String ITEM_QUEUE = "item_queue";
    //声明交换机
    @Bean("itemTopicExchange")
    public Exchange topicExchange() {
        return ExchangeBuilder.topicExchange(ITEM_TOPIC_EXCHANGE).durable(true).build();
    }
    //声明队列
    @Bean("itemQueue")
    public Queue itemQueue() {
        return QueueBuilder.durable(ITEM_QUEUE).build();
    }
    //将队列绑定到交换机
    @Bean
    public Binding itemQueueExchange(@Qualifier("itemQueue") Queue queue,
                                     @Qualifier("itemTopicExchange") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("item.#").noargs();
    }
}

配置消费者工程

1.配置applixation.yml文件,设置RibbitMQ连接参数
2.编写消息监听器监听接收队列(item_queue)消息;使用注解 @RabbitListener接收队列消息

spring:
  rabbitmq:
    host: 47.103.193.112
    post: 5672
    virtual-host: /jiajia
    username: jiajia
    password: 123456
@Component
public class MyListener {
    @RabbitListener(queues = "item_queue")
    public void myListener1(String message) {
        System.out.println("消费者接收到消息:" + message);
    }
}

测试消息发送接收

生产者:编写测试类RabbitMQTest,利用RabbitTemplate发送3条消息,路由key 分别为 item.insert 、item.update 、 item.delete
消费者:查看能否收到数据

@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitMQTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void test() {
        rabbitTemplate.convertAndSend(RabbitMQConfig.ITEM_TOPIC_EXCHANGE,
                "item.insert", "商品新增,路由key为item.insert");
        rabbitTemplate.convertAndSend(RabbitMQConfig.ITEM_TOPIC_EXCHANGE,
                "item.update", "商品修改,路由key为item.update");
        rabbitTemplate.convertAndSend(RabbitMQConfig.ITEM_TOPIC_EXCHANGE,
                "item.delete", "商品删除,路由key为item.delete");
    }
}

先启动测试类,再启动consumerApplication
测试成功
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值