rabbitMQ消息队列简介及入门代码

1:什么是消息队列

消息队列,即MQ,Message Queue

在这里插入图片描述

消息队列是典型的:生产者,消费者模式。生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产者和消费者都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,这样就实现了生产者和消费者的解耦。

例如:

  • 商品服务对商品增删改以后,无需去操作索引库,只是发送一条消息,也不关心消息被谁接收。
  • 搜索服务接收消息,处理索引库。

如果以后还有其他系统也依赖商品服务的数据,同样监听消息即可,商品服务无需任何代码修改。

2:AMQP和JMS

MQ是消息通信的模型,并不是具体实现,现在实现MQ的主要有两种方式:AMQP,JMS。

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

两者之间的区别和联系:

  • JMS是定义了统一的接口,来对消息操作进行统一。AMQP是通过规定协议里啊统一数据交互的格式。
  • JMS限定了必须使用java语言,AMQP只是协议,不规定实现方式,因此是跨语言的。
  • JMS规定了两种消息模型,而AMQP的消息模型更加丰富。

2:五中消息模型

RabbitMQ提供了6中消息模型,但是第6中其实是RPC,并不是MQ,因此我们只需要学习5中就好。

其中 3,4, 5 这三种都属于订阅模型,只不过在进行路由的方式不同。

在这里插入图片描述

我们开始一一简绍5中模型的使用方法,我们采用的是原生的代码。

1:基本消息模型(Hello,World)

RabbitMQ是一个消息代理:它接收和转发消息。你可以把它想象成一个邮局:当你把右键放在邮箱里时,你可以确定邮差最终会把右键发送给你的收件人,在这个比喻中,RabbitMQ是邮政信箱,邮局,和邮递员。

在这里插入图片描述

基本数据模型原理图解析:

P(Producer):生产者,一个发送消息的用户应用程序。

C(consument):消费者,消费者是一个主要用来等待接收消息的用户应用程序。

队列(红色区域):rabbitMQ内部类似于邮箱的一个概念。相当于生产者发送消息到队列中,消费者监听队列的是否有新消息到达,如果有就取出消息。队列是存储消息的缓冲区

我们下面正式开始编写代码:我们将创建一个生产者,一个消费者。

我们在下面的所用代码中都将使用连接工具类。

public static Connection getConnection()throws Exception {
    //定义连接工厂
    ConnectionFactory factory = new ConnectionFactory();
    //设置服务地址
    factory.setHost("*****");
    //端口
    factory.setPort(5672);
    //设置账号信息,用户名、密码、vhost
    factory.setVirtualHost("/");
    factory.setUsername("guest");
    factory.setPassword("guest");
    // 通过工程获取连接
    Connection connection = factory.newConnection();
    return connection;
}
1:代码编写
1:生产者端
public static final String QUEUE_NAME = "My_Demo";

//测试普通模式发送消息
@Test
public void send01() throws Exception{
    //获取到连接以及通道
    Connection connection = getConnection();
    Channel channel = connection.createChannel();

    //创建队列,只有创建队列才可以发送消息
    //队列是幂等的,只有当它不存在的时候在可以被创建
    channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    
    //消息内容(将对象装换为JSON串,这里网上代码很多)
    User user = new User(1,"admin","1234");
    String data = JsonUtils.objectToJson(user);
    
    channel.basicPublish("", QUEUE_NAME, null, data.getBytes());
    //关闭通道和连接
    channel.close();
    connection.close();
}

channel.basicPublish("", QUEUE_NAME, null, data.getBytes());

basicPublish方法

 void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;

void basicPublish(String exchange, String routingKey, boolean mandatory, BasicProperties props, byte[] body)
            throws IOException;

 void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate, BasicProperties props, byte[] body)
            throws IOException;
  • exchange 交换机名称
  • routingKey 路由键
  • props 消息参数
  • body 消息体,即真正需要发送的消息
  • mandatory true时,交换器无法根据自动的类型和路由键找到一个符合条件的队列,那么RabbitMq会调用Basic.Ruturn命令将消息返回给生产者,为false时,出现上述情况消息被直接丢弃
  • immediate true,如果交换器在消息路由到队列时发现没有任何消费者,那么
    这个消息将不会存和队列,当与路由匹配的所有队列都没有消费者时,会Basic.Return返回给生产者3.0去掉了immediate 参数

immediate和mandatory 都是消息传递过程中,不可达目的地是,将消息返回给生产者的功能

2:消费者获取消息
@Test
public void ConsuMent02() throws Exception {
    // 获取到连接
    Connection connection = getConnection();
    // 创建通道
    Channel channel = connection.createChannel();
    // 声明队列
    channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    // 定义队列的消费者
    Consumer consumer = new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope,
                                AMQP.BasicProperties properties, byte[] body) throws IOException {
            //获取消息内容然后处理
            String msg = new String(body, "UTF-8");
            System.err.println("*********** HelloConsumer" + " get message :[" + msg +"]");
        }
    };
    // 监听队列,第二个参数:是否自动进行消息确认。
    channel.basicConsume(QUEUE_NAME, true, consumer);
}

我们会发现,消费者获取到了消息,但是程序没有停止,一直在监听对流中是否有新的消息。一旦有新消息进入队列,就会立即打印。

2:消息确认机制(ACK)

通过刚才的案例可以看出,消息一旦消费者接受,队列中的消息就会被删除。

如果消费者进去消息后,还没执行操作就关掉了,或者抛出了异常?,消息消费失败,但是RabbitMQ无从得知,这样消息就丢失了。

因此:rabbitMQ有一个Ack机制。当消费者获取消息后,回想RabbitMQ发送回执ACK,告诉消息以及被接收,不过这种回执ACK分两种情况:

  • 自动ACK:消息一旦被接收,消费者自动发送ACK
  • 手动ACK:消息接收后,不会发送ACK,需要手动调用。

我们需要根据消息的重要性来决定使用哪种方式:

  • 如果消息不太重要,丢失也没有影响,那么自动ACK回比较方便。
  • 如果消息非常重要,不容丢失,那么最好在消费完成好手动ACK。

我们上面测试的入门Hello,world 中是自动ACK的,如果要手动ACK,需要改动消费者端的代码:

//手动确认消息
@Test
public void ConSument02() throws Exception{
    //获取连接
    Connection connection = getConnection();
    Channel channel = connection.createChannel();
    //声明队列
    channel.queueDeclare(QUEUE_NAME, false, false, false, null);

    //接收消息
    // 定义队列的消费者
    Consumer consumer = new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope,
                                   AMQP.BasicProperties properties, byte[] body) throws IOException {
            //获取消息内容然后处理
            String msg = new String(body, "UTF-8");
  System.err.println("*********** HelloConsumer" + " get message :[" + msg +"]");
            //手动确认消息代码 ↓ 
            channel.basicAck(envelope.getDeliveryTag(), false);
        }
    };
    //第二个参数代表 进行手动确认消息
    channel.basicConsume(QUEUE_NAME, false, consumer);
}

注意到最后一行代码:

channel.basicConsume(QUEUE_NAME,false,consumer);

如果第二个参数为true,就会自定进行ACK,如果为false,则需要手动ACK。

//手动确认消息代码 ↓

channel.basicAck(envelope.getDeliveryTag(), false);

以上是RabbitMQ入门,及第一章消息模型的代码。后序的消息模型代码,和整合SpringBoot,请查看我的博客目录。(在此推荐大家搜索**http://yun.itheima.com/
** 黑马程序员。RabbitMQ文章是学习了黑马视频所写。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值