消息队列的基本使用

基本概念:

  • 生产者

    向队列中发送消息的程序

  • 消费者

    从队列中消费消息的程序

  • 队列 queue

    消息的容器,FIFO数据结构

  • 交换机 exchange

    将消息复制分发到不同的队列中

  • 虚拟主机 host

    包含交换机和队列的空间

  • 连接 connection

    客户端和MQ服务的连接

  • 通道  channel

    通信的通道    

基本使用 

用户

虚拟主机

队列

交换机

五种消息模型 

RabbitMQ提供了多种消息模型,官网上第6种是RPC不属于常规的消息队列。 属于消息模型的是前5种:

  1. 简单的一对一模型

  2. 工作队列模型 ,一个生产者将消息分发给多个消费者

  3. 发布/订阅模型 ,生产者发布消息,多个消费者同时收取

  4. 路由模型 ,生产者通过关键字发送消息给特定消费者

  5. 主题模型 ,路由模式基础上,在关键字里加入了通配符

一对一模型

导入依赖

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

MQ工具类

package com.blb.rabbitmq_demo.until;

import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;

public class MQUntil {

    /**
     * 获得MQ连接
     * @return
     */
    public static Connection getMQConnection() throws IOException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
//        配置服务名、端口、虚拟主机名、登录账号和密码
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("MyGuest");
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        return connectionFactory.newConnection();
    }
}

生产者

package com.blb.rabbitmq_demo.helloword;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * 生产者发送简单的消息队列
 */
public class SimpleProduct{

    public static void main(String[] args) throws IOException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//        创建通道
        Channel channel = connection.createChannel();
//        声明队列
        channel.queueDeclare("MyQueues",false,false,false,null);
//        发送消息 交换机名,队列名,手动确认false,配置属性,数据
        channel.basicPublish("","MyQueues",false,null,"hello world".getBytes());
        channel.close();
        connection.close();
    }
}

消费者

package com.blb.rabbitmq_demo.helloword;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;

public class SimpleConsumer {

    public static void main(String[] args) throws IOException, InterruptedException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//       获得通道
        Channel channel = connection.createChannel();
//        在队列服务器上声明队列
        channel.queueDeclare("MyQueues",false,false,false,null);
//        创建消费者
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
//        消费者消息通道中的消息
        channel.basicConsume("MyQueues",true,queueingConsumer);
//        读取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            System.out.println(new String(delivery.getBody()));
        }

    }
}

运行结果

工作队列

生产者

package com.blb.rabbitmq_demo.work;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * 工作队列生产者
 * 多对多模式
 */
public class WorkProduct {

    public static void main(String[] args) throws IOException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//        创建通道
        Channel channel = connection.createChannel();
//        声明队列
        channel.queueDeclare("MyQueues",false,false,false,null);

        for (int i = 0; i < 10; i++) {
            String msg = "打印了-->" + i;
//          发送消息 交换机名,队列名,手动确认false,配置属性,数据
            channel.basicPublish("","MyQueues",false,null,msg.getBytes());
        }
        channel.close();
        connection.close();
    }
}

 消费者1

package com.blb.rabbitmq_demo.work;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;

public class WorkConsumer01 {

    public static void main(String[] args) throws IOException, InterruptedException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//       获得通道
        Channel channel = connection.createChannel();
//        在队列服务器上声明队列
        channel.queueDeclare("MyQueues",false,false,false,null);
//        限制队列一次发一个消息给消费者,等消费者有了反馈,再发下一条
        channel.basicQos(1);
//        创建消费者
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
//        消费者消息通道中的消息  true是自动返回完成状态,false表示手动
        channel.basicConsume("MyQueues",false,queueingConsumer);
//        读取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            System.out.println(new String(delivery.getBody()));
            Thread.sleep(100);
//            消费完消息后手动反馈,处理快的消费者就能处理更多消息
//            手动确定返回状态,不写就是自动确认
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        }

    }
}

消费者2

package com.blb.rabbitmq_demo.work;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;

public class WorkConsumer02 {

    public static void main(String[] args) throws IOException, InterruptedException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//       获得通道
        Channel channel = connection.createChannel();
//        在队列服务器上声明队列
        channel.queueDeclare("MyQueues",false,false,false,null);
        //        限制队列一次发一个消息给消费者,等消费者有了反馈,再发下一条
        channel.basicQos(1);
//        创建消费者
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
//        消费者消息通道中的消息
        channel.basicConsume("MyQueues",false,queueingConsumer);
//        读取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            System.out.println(new String(delivery.getBody()));
            Thread.sleep(300);
//            消费完消息后手动反馈,处理快的消费者就能处理更多消息
//            手动确定返回状态,不写就是自动确认
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        }

    }
}

上边代码已经实现能者多劳:

  1. channel.basicQos(1);限制队列一次发一个消息给消费者,等消费者有了反馈,再发下一条

  2. channel.basicAck 消费完消息后手动反馈,处理快的消费者就能处理更多消息

  3. basicConsume 中的参数改为false

发布订阅模式

 生产者

package com.blb.rabbitmq_demo.publish;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * 发布和订阅模式生产者
 * 消息会通过交换机发送到队列
 */
public class PublishProduct {

    public static void main(String[] args) throws IOException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//        创建通道
        Channel channel = connection.createChannel();
//      声明交换机 fanout扇出
        channel.exchangeDeclare("MyExchange","fanout");
        String msg = "hello fanout";
//        发布到交换机
        channel.basicPublish("MyExchange","",null,msg.getBytes());
        channel.close();
        connection.close();
    }
}

消费者1

package com.blb.rabbitmq_demo.publish;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;

/**
 *   发布订阅模式的消费者1
 *   两个消费者绑定的消息队列不同
 *   通过交换机一个消息能被不同队列的两个消费者同时获取
 *   一个队列可以有多个消费者,队列中的消息只能被一个消费者获取
 */
public class PublishConsumer01 {

    public static void main(String[] args) throws IOException, InterruptedException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//       获得通道
        Channel channel = connection.createChannel();
//        在队列服务器上声明队列
        channel.queueDeclare("MyQueues",false,false,false,null);
//      绑定队列1到交换机上
        channel.queueBind("MyQueues","MyExchange","");
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
        channel.basicConsume("MyQueues",true,queueingConsumer);
//        读取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            System.out.println("消费者1-->"+new String(delivery.getBody()));
        }

    }
}

消费者2

package com.blb.rabbitmq_demo.publish;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;

public class PublishConsumer02 {

    public static void main(String[] args) throws IOException, InterruptedException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//       获得通道
        Channel channel = connection.createChannel();
//        在队列服务器上声明队列
        channel.queueDeclare("MyQueues1",false,false,false,null);
//      绑定队列1到交换机上
        channel.queueBind("MyQueues1","MyExchange","");
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
        channel.basicConsume("MyQueues1",true,queueingConsumer);
//        读取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            System.out.println("消费者2-->"+new String(delivery.getBody()));
        }

    }
}

路由模式

生产者

package com.blb.rabbitmq_demo.direct;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * 路由模式的生产者,发布消息会有特定的Key,消息会被绑定特定Key的消费者获取
 */
public class DirectProduct {

    public static void main(String[] args) throws IOException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//        创建通道
        Channel channel = connection.createChannel();
//      声明交换机 direct
        channel.exchangeDeclare("MyExchange2","direct");
        String msg = "hello direct";
//        绑定队列1到交换机,指定key为error
        channel.queueBind("MyQueues1","MyExchange2","error");
//        绑定队列2到交换机,指定key为error
        channel.queueBind("MyQueues2","MyExchange2","debug");
//        发布到交换机
        channel.basicPublish("MyExchange2","error",null,msg.getBytes());
        channel.basicPublish("MyExchange2","debug",null,msg.getBytes());
        channel.close();
        connection.close();
    }
}

消费者1

package com.blb.rabbitmq_demo.direct;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;

/**
 * 路由模式的消费者1
 * 可以指定Key,消费特定的消息
 */
public class DirectConsumer01 {

    public static void main(String[] args) throws IOException, InterruptedException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//       获得通道
        Channel channel = connection.createChannel();
//        在队列服务器上声明队列
        channel.queueDeclare("MyQueues1",false,false,false,null);
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
        channel.basicConsume("MyQueues1",true,queueingConsumer);
//        读取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            System.out.println("消费者1-->"+new String(delivery.getBody()));
        }

    }
}

消费者2

package com.blb.rabbitmq_demo.direct;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;

/**
 * 路由模式的消费者1
 * 可以指定Key,消费特定的消息
 */
public class DirectConsumer02 {

    public static void main(String[] args) throws IOException, InterruptedException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//       获得通道
        Channel channel = connection.createChannel();
//        在队列服务器上声明队列
        channel.queueDeclare("MyQueues2",false,false,false,null);
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
        channel.basicConsume("MyQueues2",true,queueingConsumer);
//        读取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            System.out.println("消费者2-->"+new String(delivery.getBody()));
        }

    }
}

主题模式

生产者

package com.blb.rabbitmq_demo.topic;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;

/**
 * 主题模式的生产者
 *   *		  匹配任意一个单词    com.*
 *   #        匹配.号隔开的多个单词 com.#
 */
public class TopicProduct {

    public static void main(String[] args) throws IOException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//        创建通道
        Channel channel = connection.createChannel();
//      声明交换机 direct
        channel.exchangeDeclare("MyExchange3","topic");
//        绑定队列1到交换机,指定key
        channel.queueBind("MyQueues1","MyExchange3","*.cn");
//        绑定队列2到交换机,指定key
        channel.queueBind("MyQueues2","MyExchange3","#.com");
//        发布到交换机
        channel.basicPublish("MyExchange3","blb.lg.com",null,"blb.lg.cn".getBytes());
        channel.basicPublish("MyExchange3","blb.cn",null,"blb.cn".getBytes());
        channel.basicPublish("MyExchange3","blb.com",null,"blb.com".getBytes());
        channel.close();
        connection.close();
    }
}

消费者1

package com.blb.rabbitmq_demo.topic;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;

/**
 * 主题模式的消费者1 ,类似路由模式,可以使用通配符对Key进行筛选
 *   #匹配1个或多个单词,*匹配一个单词
 */
public class TopicConsumer01 {

    public static void main(String[] args) throws IOException, InterruptedException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//       获得通道
        Channel channel = connection.createChannel();
//        在队列服务器上声明队列
        channel.queueDeclare("MyQueues1",false,false,false,null);
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
        channel.basicConsume("MyQueues1",true,queueingConsumer);
//        读取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            System.out.println("消费者1-->"+new String(delivery.getBody()));
        }

    }
}

消费者2

package com.blb.rabbitmq_demo.topic;

import com.blb.rabbitmq_demo.until.MQUntil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

import java.io.IOException;

/**
 * 主题模式的消费者2 ,类似路由模式,可以使用通配符对Key进行筛选
 *   #匹配1个或多个单词,*匹配一个单词
 */
public class TopicConsumer02 {

    public static void main(String[] args) throws IOException, InterruptedException {
//        获得连接
        Connection connection = MQUntil.getMQConnection();
//       获得通道
        Channel channel = connection.createChannel();
//        在队列服务器上声明队列
        channel.queueDeclare("MyQueues2",false,false,false,null);
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
        channel.basicConsume("MyQueues2",true,queueingConsumer);
//        读取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            System.out.println("消费者2-->"+new String(delivery.getBody()));
        }

    }
}

总结

模式有:

  1. 一对一

  2. 一对多

    前两种都只有一个队列,多个消费者共享一个队列中的消息

  3. 发布订阅模式

    由交换机绑定多个队列,每个消费者消费自己的队列中的消息

  4. 路由模式

    在发布订阅模式的基础上,加入路由键,消息通过键路由到不同的队列

  5. 主题模式

    在路由模式基础上,键中加入通配符

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值