RabbitMq消息队列

参考:https://blog.csdn.net/hellozpc/article/details/81436980

什么是消息队列

MQ :message Queue ,实际上是一个队列,先进先出,队列中存放的是message

主要用途:不同进程process/线程Thread之间的通信

产生消息队列的原因

1.不同进程(process)之间传递消息时,两个进程之间耦合程度过高,改动一个进程,引发必须修改另一个进程

2.不同进程(process)之间传递消息时,为了实现标准化,将消息的格式规范化

3.某一个进程接受的消息太多,一下子无法处理完,并且也有先后顺序,必须对收到的消息进行排队

RabbitMq的特点

1.实现应用程序和应用程序之间的通信

2.使用Erlang编写,Erlang是一种并发的编程语言

什么叫AMQP

AMQP: 是消息队列的一个协议

如何使用RabbitMQ

1.安装Erlang

2.安装RabbitMQ

搭建RabbitMQ环境 ------》 登录RabbitMQ -------- > 设置用户,密码,vhost ----- >获取端口号 -----》此时就拥 有了一个RabbirMQ

两个应用之间的通信先经过RabbitMQ

RabbitMQ的5种队列

一个生产者 一个队列 一个消费者:

实现:

1.建立客户端

导入客户端依赖包:amqp-client.jar

建立工厂,配置工厂信息(RabbitMQ的用户账号,密码,端口号,vhost)与MQ连接

 /**
ConnectionUtils类
*/
//ConnectionFactory来自com.rabbitmq.client.ConnectionFactory
ConnectionFactory factory = new ConnectionFactory()
//配置工厂信息
factory.setHost("localhost") //设置服务地址
factory.setPort("5672")
factory.setVirtualhost("testhost") //在RabbitMQ上创建的虚拟的主机名称
factory.setUserName("admin") //在RabbitMq上设置的账号
factory.setPassword("admin") //根据工厂建立连接
Connection conn = factory.nwe Connection() // com.rabbitmq.client.Connection
return conn;

生产者发送消息到队列

private final static String QUEUE_NAME = "q_test_01"
//获取连接
Connection conn = ConnectionUtil.getConnection()
//通过连接建立通道
Channel channel = conn.createChannel();
//通过通道创建一个队列
channel.QueueDeclare(QUEUE_NAME,false,false,false,null);
//通过通道向对列传递信息
String message = "hhh";
channel.basicPublish("",QUEUE_NAME,false,message.getByte())

生产者做的事情:

1.与RabbitMQ建立连接(conn = getConnection()),

2.之后建立通道(channel = conn.createChannel()),

3.在通道上建立队列(channel.queueDclare("name")),

4.通过通道往队列发送信息(channel.basicPublish())

消费者消费队列的信息

private final static String QUEUE_NAME = "q_test_01"
//获取连接
Connection conn = ConnectionUtil.getConnection()
//通过连接建立通道
Channel channel = conn.createChannel();
//通过通道声明一个队列
channel.QueueDeclare(QUEUE_NAME,false,false,false,null);
//定义队列的消费者
QueueingConsummer consummer = new QueueingConsumer(channel);
//监听队列
channel.basicCosume(QUEUE_NAME,true,consummer);
//获取队列的信息
while(true){
QueueingConsummer.Delively delivery = comsummer.nextDelivery();
String message = new String(delivery.getBody())
}

生产者做的事情:

1.与RabbitMQ建立连接conn = getConnection()

2.建立通道channel = conn.createChannel()

3.声明队列channel.queueDeclare("name")

4.建立通道里的消费者QueueingConsumer consumer = new Consummer(channel)

5.监听队列信息 basicConsume("队列名称",true,consumer)

6.获取数据 comsummer.nextDelivery()

work模式,一个生产者,一个队列,多个消费者

消费者1接受收信息

private final static String QUEUE_NAME = "q_test_01"
//获取连接
Connection conn = ConnectionUtil.getConnection()
//通过连接建立通道
Channel channel = conn.createChannel();
//通过通道声明一个队列
channel.QueueDeclare(QUEUE_NAME,false,false,false,null);
//同一时刻服务器只会发一条信息给消费者
channel.basicQos)(1)
//定义消费者
QueueingConsummer consummer = new QueueingConsummer(channel);
//监听队列
channel.basicComsume("QUEUE_NAME",true,consumer)
//获取队列的信息
while(true){
QueueingConsummer.Delively delivery = comsummer.nextDelivery();
String message = new String(delivery.getBody())
//休眠
Thread.sleep(10)
// 返回确认状态,注释掉表示使用自动确认模式
//channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}

消费者2接收信息

private final static String QUEUE_NAME = "q_test_01"
//获取连接
Connection conn = ConnectionUtil.getConnection()
//通过连接建立通道
Channel channel = conn.createChannel();
//通过通道声明一个队列
channel.QueueDeclare(QUEUE_NAME,false,false,false,null);
//同一时刻服务器只会发一条信息给消费者
channel.basicQos)(1)
//定义消费者
QueueingConsummer consummer = new QueueingConsummer(channel);
//监听队列,false表示手动返回完成状态,true表示自动
channel.basicComsume("QUEUE_NAME",true,consumer)
//获取队列的信息
while(true){
QueueingConsummer.Delively delivery = comsummer.nextDelivery();
String message = new String(delivery.getBody())
//休眠1秒
Thread.sleep(1000)
// 返回确认状态,注释掉表示使用自动确认模式
//channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}

测试结果:

生产者生产100条信息,消费1个消费2一起去消费信息,消费1消费一条信息睡眠0.01秒,消费2消费一条信息睡眠1秒,最后两个消费者消费的信息个数相等,且不重复(轮询分发:消息按顺序的发送给消费者)

按常理来说应该睡眠时间断的消费者得到的信息条数更多

如何解决这一问题呢?

通过Qos,和Acknowledge(告知已收到)来解决

basicQos 方法设置了当前信道最大预获取(prefetch)消息数量为1

basicQos(1):

消息从队列异步推送给消费者,消费者的 ack 也是异步发送给队列 ,队列只有在收到消费者发回的上一条消息 ack 确认后,才会向该消费者发送下一条消息

basicQos(0):

没有限制,队列会将所有消息尽快发给消费者

公平分发:

使用basicQos( prefetchCount = 1)方法 ,限制RabbitMQ只发不超过1条的消息给同一个消费者。当消息处理完毕后,有了反馈,才会进行第二次发送

使用公平分发,必须关闭自动应答,改为手动应答

//使用手动确认模式
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); // 监听队列,false表示手动返回完成状态,true表示自动
channel.basicConsume(QUEUE_NAME, false, consumer);

订阅模式(exchange)

fanout exchange (广播模式)

特点:多个队列,一个队列对应一个用户,生产者将信息发送到exchange中,通过exchange发送给绑定的队列,消费者从对应的队列中消费信息,这样,所有的消费者就可以消费相同的信息

生产者生成

package com.zpc.rabbitmq.subscribe;

import com.zpc.rabbitmq.util.ConnectionUtil;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection; public class Send { private final static String EXCHANGE_NAME = "test_exchange_fanout"; public static void main(String[] argv) throws Exception {
// 获取到连接以及mq通道
Connection connection = ConnectionUtil.getConnection();
Channel channel = connection.createChannel(); // 声明exchange
channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); // 消息内容
String message = "Hello World!";
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'"); channel.close();
connection.close();
}
}

消费者消费

public class Recv {

    private final static String QUEUE_NAME = "test_queue_work1";

    private final static String EXCHANGE_NAME = "test_exchange_fanout";

    public static void main(String[] argv) throws Exception {

        // 获取到连接以及mq通道
Connection connection = ConnectionUtil.getConnection();
Channel channel = connection.createChannel(); // 声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null); // 绑定队列到交换机
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); // 同一时刻服务器只会发一条消息给消费者
channel.basicQos(1); // 定义队列的消费者
QueueingConsumer consumer = new QueueingConsumer(channel);
// 监听队列,手动返回完成
channel.basicConsume(QUEUE_NAME, false, consumer); // 获取消息
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(" [Recv] Received '" + message + "'");
Thread.sleep(10); channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
}
}

声明exchange: channel.exchangeDeclare("交换机的名字","交换机的类型")

                        channel.exchangeDeclare("交换机名","fanout")

                        fanout:广播式交换机,所有队列都能接受信息

向交换机发送数据:channel.basicPublish("交换机名","", null, message.getByte())

队列与交换机绑定:channel.queueBind("队列名","交换机名")

Direct exchange (exchange的key与queue的key一一匹配模式)

生产者生产:

生产者创建交换机时声明交换机的类型

channel.exchangeDeclare("交换机名称","direct") //声明交换机的类型为direct

发送数据时指定接受的队列,key值与队列的key值一一对应

channel.basicPublish("交换机名称","路由到queue的key值",null,message.getBytes())

消费者消费:

channel.queueBind("队列名称",”交换机名称“,"队列与交换机的key值一一对应")

topic模糊匹配模式

"#":匹配所有数据

"*":匹配单个数据

生产者发送数据时声明key值

两个交换机:

channel.exchangeDeclare("交换机1","topic")

channel.basicPublish("交换机1","user.news",null,message.getBytes());

channel.basicPublish("j交换机1","user.weather",null,message.getByutes())

消费者绑定交换机:

消费者一:

channel.queueBind("队列名称","交换机名称","user.*")

RabbitMQ的入门学习的更多相关文章

  1. RabbitMQ从入门到精通

    RabbitMQ从入门到精通 学习了:http://blog.csdn.net/column/details/rabbitmq.html RabbitMQ是AMQP(advanced message ...

  2. 中小研发团队架构实践之RabbitMQ快速入门及应用

    原文:中小研发团队架构实践之RabbitMQ快速入门及应用 使用过分布式中间件的人都知道,程序员使用起来并不复杂,常用的客户端API就那么几个,比我们日常编写程序时用到的API要少得多.但是分布式中间 ...

  3. ASP.NET Core消息队列RabbitMQ基础入门实战演练

    一.课程介绍 人生苦短,我用.NET Core!消息队列RabbitMQ大家相比都不陌生,本次分享课程阿笨将给大家分享一下在一般项目中99%都会用到的消息队列MQ的一个实战业务运用场景.本次分享课程不 ...

  4. ASP.NET Core on K8S 入门学习系列文章目录

    一.关于这个系列 自从2018年底离开工作了3年的M公司加入X公司之后,开始了ASP.NET Core的实践,包括微服务架构与容器化等等.我们的实践是渐进的,当我们的微服务数量到了一定值时,发现运维工 ...

  5. RabbitMQ由浅入深入门全总结(一)

    写在最前面 距离上一次发文章已经很久了,其实这段时间一直也没有停笔,只不过在忙着找工作还有学校结课的事情,重新弄了一下博客,后面也会陆陆续续会把文章最近更新出来~ 这篇文章有点长,就分了两篇Q PS: ...

  6. vue入门学习(基础篇)

    vue入门学习总结: vue的一个组件包括三部分:template.style.script. vue的数据在data中定义使用. 数据渲染指令:v-text.v-html.{{}}. 隐藏未编译的标 ...

  7. Hadoop入门学习笔记---part4

    紧接着<Hadoop入门学习笔记---part3>中的继续了解如何用java在程序中操作HDFS. 众所周知,对文件的操作无非是创建,查看,下载,删除.下面我们就开始应用java程序进行操 ...

  8. Hadoop入门学习笔记---part3

    2015年元旦,好好学习,天天向上.良好的开端是成功的一半,任何学习都不能中断,只有坚持才会出结果.继续学习Hadoop.冰冻三尺,非一日之寒! 经过Hadoop的伪分布集群环境的搭建,基本对Hado ...

  9. PyQt4入门学习笔记(三)

    # PyQt4入门学习笔记(三) PyQt4内的布局 布局方式是我们控制我们的GUI页面内各个控件的排放位置的.我们可以通过两种基本方式来控制: 1.绝对位置 2.layout类 绝对位置 这种方式要 ...

随机推荐

  1. 2019.10.28 CSP%您赛第四场t3

    我写不动前两个了. 原谅一下. ____________________________________________________________________________________ ...

  2. CheckBox状态多选

    前: <StackPanel Margin="> <Label FontWeight="Bold">Application Options< ...

  3. 自定义表头Datagrid

    自定义的一个表头 <bp:BasePage x:Class="NetReform.Pages.RealProbabiTableCompare" xmlns="htt ...

  4. SpringBoot 配置提示功能

    目的 配置自动提示的辅助功能可以让配置写起来更快,准确率大大提高. springboot jar 包含提供所有支持的配置属性细节的元数据文件.文件的目的是为了让 IDE 开发者在用户使用 applic ...

  5. redis入门(一)

    目录 redis入门(一) 前言 特性 速度快 简单稳定 丰富的功能 历史 历史版本 安装与启动 安装 数据类型与内部编码 数据结构 内部编码 常用API与使用场景 常用命令 字符串 列表 哈希 集合 ...

  6. fenby C语言

    P1框架 1#include <stdio.h> 2 3int main(){ 4    printf(“C语言我来了”); 5    return 0; 6} P2main()门 P3计 ...

  7. 用Unity做游戏,你需要深入了解一下IL2CPP

    这次我们翻译了一篇Unity官方博客上的文章,原文题目为AN INTRODUCTION TO IL2CPP INTERNALS ,作者是从事Unity软件开发的Joshua Peterson.文章的看 ...

  8. 微服务架构案例(05):SpringCloud 基础组件应用设计

    本文源码:GitHub·点这里 || GitEE·点这里 更新进度(共6节): 01:项目技术选型简介,架构图解说明 02:业务架构设计,系统分层管理 03:数据库选型,业务数据设计规划 04:中间件 ...

  9. C语言I博客作业04

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/SE2019-1/homework/9773 我在这个课程的目标 ...

  10. K近邻(k-Nearest Neighbor,KNN)算法,一种基于实例的学习方法

    1. 基于实例的学习算法 0x1:数据挖掘的一些相关知识脉络 本文是一篇介绍K近邻数据挖掘算法的文章,而所谓数据挖掘,就是讨论如何在数据中寻找模式的一门学科. 其实人类的科学技术发展的历史,就一直伴随 ...