第一种模式=直连

  • P:生产者,也就是要发送消息的程序

  • C:消费者:消息的接受者,会一直等待消息到来。

  • queue:消息队列,图中红色部分。类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。

producer:

package com.quan.rabbitmq.producer;

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 RMQProducer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("quan");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("quan"); Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare("hello",true,false,false,null);
channel.basicPublish("","hello",null,"hello rabbit".getBytes()); channel.close();
connection.close();
} }

consumer:

package com.quan.rabbitmq.consumer;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException; public class RMQConsumer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("quan");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("quan");
//创建连接
Connection connection = connectionFactory.newConnection();
//通过连接创建通道
Channel channel = connection.createChannel(); /**
* 参数1:声明通道对应的队列
* 参数2:指定是否持久化
* 参数3:指定是否独占对象
* 参数4:指定是否自动删除队列
* 参数5:对队列的额外设置
*/
channel.queueDeclare("hello",true,false,false,null);
channel.basicConsume("hello",true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body));
}
}); } }

第二种模式=任务模型(work quene)

当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,无法及时处理。

此时就可以使用work 模型:让多个消费者绑定到一个队列,共同消费队列中的消息。队列中的消息一旦消费,就会消失,因此任务是不会被重复执行的。

  • P:生产者:任务的发布者

  • C1:消费者-1,领取任务并且完成任务,假设完成速度较慢

  • C2:消费者-2:领取任务并完成任务,假设完成速度快

P:

/**
* 直连模型:
* 生产者发送消息
* 消费者,等待消息到来消费
* 消息队列:可以缓存消息,生产者向其中投递消息,消费者从其中取出消息。
*
*/
public class RMQProducer2 {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("quan");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("quan"); Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare("hello",true,false,false,null);
for(int i =0 ;i<20;i++){
channel.basicPublish("","hello",null,(i+"=====>hello rabbit").getBytes());
} channel.close();
connection.close();
} }

C1

public class RMQConsumer21 {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("quan");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("quan");
//创建连接
Connection connection = connectionFactory.newConnection();
//通过连接创建通道
Channel channel = connection.createChannel(); /**
* 参数1:声明通道对应的队列
* 参数2:指定是否持久化
* 参数3:指定是否独占对象
* 参数4:指定是否自动删除队列
* 参数5:对队列的额外设置
*/
channel.queueDeclare("hello",true,false,false,null);
channel.basicConsume("hello",true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("我是consumer1"+new String(body));
}
}); } }

C2

public class RMQConsumer22 {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("quan");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("quan");
//创建连接
Connection connection = connectionFactory.newConnection();
//通过连接创建通道
Channel channel = connection.createChannel(); /**
* 参数1:声明通道对应的队列
* 参数2:指定是否持久化
* 参数3:指定是否独占对象
* 参数4:指定是否自动删除队列
* 参数5:对队列的额外设置
*/
channel.queueDeclare("hello",true,false,false,null);
channel.basicConsume("hello",true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是consumer2"+new String(body));
}
});
}
}

re

当两个消费者都在监听通道中的消息的时候:

我们一旦发消息:

我是consumer2    0=====>hello rabbit
我是consumer2 2=====>hello rabbit
我是consumer2 4=====>hello rabbit
我是consumer2 6=====>hello rabbit
我是consumer2 8=====>hello rabbit
我是consumer2 10=====>hello rabbit
我是consumer2 12=====>hello rabbit
我是consumer2 14=====>hello rabbit
我是consumer2 16=====>hello rabbit
我是consumer2 18=====>hello rabbit @@@@@@@@@@@@@@ 我是consumer1 1=====>hello rabbit
我是consumer1 3=====>hello rabbit
我是consumer1 5=====>hello rabbit
我是consumer1 7=====>hello rabbit
我是consumer1 9=====>hello rabbit
我是consumer1 11=====>hello rabbit
我是consumer1 13=====>hello rabbit
我是consumer1 15=====>hello rabbit
我是consumer1 17=====>hello rabbit
我是consumer1 19=====>hello rabbit

默认情况下,RabbitMQ将按顺序将每个消息发送给下一个使用者。平均而言,每个消费者都会收到相同数量的消息。这种分发消息的方式称为循环。

消息确认机制:

public class RMQConsumer21 {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("quan");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("quan");
//创建连接
Connection connection = connectionFactory.newConnection();
//通过连接创建通道
final Channel channel = connection.createChannel(); channel.queueDeclare("hello",true,false,false,null); channel.basicQos(1);//一次只接受一条为确认的消息
//第二个参数:关闭自动确认消息
channel.basicConsume("hello",false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("我是consumer1 "+new String(body));
channel.basicAck(envelope.getDeliveryTag(),false);//手动确认消息
}
}); } }

re:

我是consumer1    0=====>hello rabbit

@@@@@@@@@@@

我是consumer2    1=====>hello rabbit
我是consumer2 2=====>hello rabbit
我是consumer2 3=====>hello rabbit
我是consumer2 4=====>hello rabbit
我是consumer2 5=====>hello rabbit
我是consumer2 6=====>hello rabbit
我是consumer2 7=====>hello rabbit
我是consumer2 8=====>hello rabbit
我是consumer2 9=====>hello rabbit
我是consumer2 10=====>hello rabbit
我是consumer2 11=====>hello rabbit
我是consumer2 12=====>hello rabbit
我是consumer2 13=====>hello rabbit
我是consumer2 14=====>hello rabbit
我是consumer2 15=====>hello rabbit
我是consumer2 16=====>hello rabbit
我是consumer2 17=====>hello rabbit
我是consumer2 18=====>hello rabbit
我是consumer2 19=====>hello rabbit

第三种模式-广播

fanout 扇出===广播

消息发送流程:

-  可以有多个消费者
- 每个消费者有自己的queue(队列)
- 每个队列都要绑定到Exchange(交换机)
- 生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定。
- 交换机把消息发送给绑定过的所有队列
- 队列的消费者都能拿到消息。实现一条消息被多个消费者消费

p;更新部分:

        Connection connection = connectionFactory.newConnection();

        Channel channel = connection.createChannel();

       channel.exchangeDeclare("logs","fanout");
for(int i =0 ;i<20;i++){
//第一个参数:交换机名字
//第二个参数:队列名字
//第三个参数:
//第四个参数:消息,是byte类型
channel.basicPublish("logs","",null,(i+"=====>hello rabbit").getBytes());
}

c1 c2 c3:这三个都是差不多的配置:

     //绑定交换机
channel.exchangeDeclare("logs","fanout");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//将临时队列绑定交换机exchange
channel.queueBind(queue,"logs","");
//处理消息
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("我是consumer1 "+new String(body)); }
});

re:

所有的消息,每个消费者都可以消费得到,

第四种模式-Routing-订阅模式中的-直连(direct)

在Fanout模式中,一条消息,会被所有订阅的队列都消费。但是,在某些场景下,我们希望不同的消息被不同的队列消费

这时就要用到Direct类型的Exchange。

流程:

- 队列与交换机的绑定,不能是任意绑定了,而是要指定一个`RoutingKey`(路由key)
- 消息的发送方在 向 Exchange发送消息时,也必须指定消息的 `RoutingKey`。
- Exchange不再把消息交给每一个绑定的队列,而是根据消息的`Routing Key`进行判断,只有队列的`Routingkey`与消息的 `Routing key`完全一致,才会接收到消息

- P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。
- X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与routing key完全匹配的队列
- C1:消费者,其所在队列指定了需要routing key 为 error 的消息
- C2:消费者,其所在队列指定了需要routing key 为 info、error、warning 的消息

 情景:

c1 :error,info,debug

c2:error

c3:info

p:会每种key发一条消息:

p:改变rkey的值:

        //声明交换机:参数1:交换机名称
//参数2:交换机类型:
channel.exchangeDeclare("logs1","direct");
String rkey = "debug";
//第一个参数:交换机名字
//第二个参数:队列名字/路由key
//第三个参数:
//第四个参数:消息,是byte类型
channel.basicPublish("logs1",rkey,null,(rkey+"消息=====>hello rabbit").getBytes());
channel.close();
connection.close();
}

c1:

  //绑定交换机/参数2 交换机类型
channel.exchangeDeclare("logs1","direct");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//将临时队列绑定交换机exchange
//第一个参数:队列,第2个参数:交换机名字,第3个参数:路由key
channel.queueBind(queue,"logs1","error");
channel.queueBind(queue,"logs1","info");
channel.queueBind(queue,"logs1","debug");
//处理消息
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("我是consumer1 "+new String(body)); }
}); }

c2:

   //绑定交换机
channel.exchangeDeclare("logs1","direct");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//将临时队列绑定交换机exchange
//第一个参数:队列,第2个参数:交换机名字,第3个参数:路由key
channel.queueBind(queue,"logs1","error");
//处理消息

C3:

  //创建连接
Connection connection = connectionFactory.newConnection();
//通过连接创建通道
Channel channel = connection.createChannel(); //绑定交换机
channel.exchangeDeclare("logs1","direct");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//将临时队列绑定交换机exchange
//第一个参数:队列,第2个参数:交换机名字,第3个参数:路由key
channel.queueBind(queue,"logs1","info");
//处理消息

p每个rkey发送一次消息后的结果:

我是consumer1    error消息=====>hello rabbit
我是consumer1 info消息=====>hello rabbit
我是consumer1 debug消息=====>hello rabbit 我是consumer2 error消息=====>hello rabbit 我是consumer3 info消息=====>hello rabbit

可以知道,这种类型的交换机是可以按需发送的。

Routing的订阅模式--topic:

Topic类型的ExchangeDirect相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列

在绑定Routing key 的时候使用通配符!

这种模型Routingkey 一般都是由一个或多个单词组成,多个单词之间以”.”分割,例如: item.insert

p:

 //声明交换机:参数1:交换机名称
//参数2:交换机类型:
channel.exchangeDeclare("topic1","topic");
String rkey = "user.debug.all";
//第一个参数:交换机名字
//第二个参数:队列名字/路由key
//第三个参数:
//第四个参数:消息,是byte类型
channel.basicPublish("topic1",rkey,null,(rkey+"消息=====>hello rabbit").getBytes());

c2:

        //绑定交换机
channel.exchangeDeclare("topic1","topic");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//将临时队列绑定交换机exchange
//第一个参数:队列,第2个参数:交换机名字,第3个参数:路由key
channel.queueBind(queue,"topic1","user.#");

user.#可以匹配多个后面的单词:

c1:

     //绑定交换机/参数2 交换机类型
channel.exchangeDeclare("topic1","topic");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//将临时队列绑定交换机exchange
//第一个参数:队列,第2个参数:交换机名字,第3个参数:路由key
channel.queueBind(queue,"topic1","user.*");

user.*只能接一个单词:

p发送了一次key为user.debug 和一次user.debug.all:

我是consumer1    user.debug消息=====>hello rabbit

我是consumer2    user.debug消息=====>hello rabbit
我是consumer2 user.debug.all消息=====>hello rabbit

RabbitMQ-learning的更多相关文章

  1. Scheduled Jobs with Custom Clock Processes in Java with Quartz and RabbitMQ

    原文地址: https://devcenter.heroku.com/articles/scheduled-jobs-custom-clock-processes-java-quartz-rabbit ...

  2. NServiceBus+RabbitMQ开发分布式应用

    前言      NServiceBus提供了8种传输管道组件,分别是Learning.MSMQ.Azure Service Bus.Azure Service Bus (Legacy).Azure S ...

  3. 消息队列——RabbitMQ学习笔记

    消息队列--RabbitMQ学习笔记 1. 写在前面 昨天简单学习了一个消息队列项目--RabbitMQ,今天趁热打铁,将学到的东西记录下来. 学习的资料主要是官网给出的6个基本的消息发送/接收模型, ...

  4. RabbitMq应用二

    在应用一中,基本的消息队列使用已经完成了,在实际项目中,一定会出现各种各样的需求和问题,rabbitmq内置的很多强大机制和功能会帮助我们解决很多的问题,下面就一个一个的一起学习一下. 消息响应机制 ...

  5. 【Machine Learning】KNN算法虹膜图片识别

    K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  6. 如何优雅的使用RabbitMQ

    RabbitMQ无疑是目前最流行的消息队列之一,对各种语言环境的支持也很丰富,作为一个.NET developer有必要学习和了解这一工具.消息队列的使用场景大概有3种: 1.系统集成,分布式系统的设 ...

  7. RabbitMq应用一的补充(RabbitMQ的应用场景)

    直接进入正题. 一.异步处理 场景:发送手机验证码,邮件 传统古老处理方式如下图 这个流程,全部在主线程完成,注册->入库->发送邮件->发送短信,由于都在主线程,所以要等待每一步完 ...

  8. RabbitMq应用一

    RabbitMq应用一 RabbitMQ的具体概念,百度百科一下,我这里说一下我的理解,如果有少或者不对的地方,欢迎纠正和补充. 一个项目架构,小的时候,一般都是传统的单一网站系统,或者项目,三层架构 ...

  9. 【Machine Learning】Python开发工具:Anaconda+Sublime

    Python开发工具:Anaconda+Sublime 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现 ...

  10. 【Machine Learning】机器学习及其基础概念简介

    机器学习及其基础概念简介 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

随机推荐

  1. CVE-2021-40449 NtGdiResetDC UAF

    背景   CVE-2021-40449是一个存在于Win32k内核驱动中的UAF漏洞.该漏洞在2021年八月下旬九月上旬被Kaspersky发现用于野外攻击活动中.通过Hook win32k驱动执行N ...

  2. 完爆Excel!一个令人惊艳的数据展示工具,让你做图更轻松高效

    数据展示应该是最常见的需求,我们经常利用数据做总结.用数据做分享.但是我们该如何更好地展示给我们需要展示的人,如何才能让我们的数据表达更加动人,这个值得让人思索. 说到数据表达,常用的数据展示方式无非 ...

  3. 深度剖析数仓CN增量备份技术

    摘要:为了解决Roach的性能问题,提出了CN增量备份手段,从而达到进一步优化RPO目的. 本文分享自华为云社区<GaussDB(DWS)备份容灾之CN增量备份>,作者: zxy_db . ...

  4. Oracle之表和字段的注释

    给表名加上注释 --给表名加上注释的语法结构 --语法结构:COMMENT ON TABLE 英文表名 IS '中文注释' COMMENT ON TABLE DEPT IS '部门表'; 给字段加上注 ...

  5. Redis学习笔记(详细)

    目录 概述 Redis安装启动 常用五大数据类型 Redis键(key) Redis字符串(String) Redis列表(List) Redis集合(Set) Redis哈希(Hash) Redis ...

  6. linux centos7下 c++编程

    在Linux下与在windos下编程没啥区别,可以在windos上实现后,然后更改一些,移植到linux中 yum install gcc yum install gcc-c++ vi main.cp ...

  7. WPS二级标题链接到一级标题

    WPS二级标题链接到一级标题,即2后出现2.1 2.2而不是1.3 1.4什么的 样式中的编号什么的都不用动,默认即可,关键在于这些多级标题是否选择了同一个编号方式 WPS中,只需要将它们的编号选择为 ...

  8. 02-asio学习

    https://blog.csdn.net/weixin_42881084/article/details/101996032 https://blog.csdn.net/Marble_ccp/art ...

  9. 前端人员不要只知道KFC,你应该了解 BFC、IFC、GFC 和 FFC

    前言 说起KFC,大家都知道是肯德基,但面试官问你什么是BFC.IFC.GFC和FFC的时候,你是否能够像回答KFC是肯德基时的迅速,又或者说后面这些你根本就没听说过,作为一名前端开发工程师,以上这些 ...

  10. JZ-056-删除链表中重复的结点

    删除链表中重复的结点 题目描述 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4-> ...