第一种模式=直连

  • 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. 『德不孤』Pytest框架 — 7、Pytest预期失败

    目录 1.@pytest.mark.xfail()标记的作用 2.应用场景 3.语法参数说明 4.示例 5.忽略xfail标识 Pytest预期失败需要使用@pytest.mark.xfail()标记 ...

  2. 攻防世界Web_shrine

    题目: 给的是源代码,整理一下如下: 看到jinjia flask,render_template_string猜测到这题应该是考查python模板注入. 代码分析可以得到以下信息: 1.路径在 /s ...

  3. 解决overlay2存储驱动的磁盘配额问题

    为啥要用overlay2 docker centos(内核3.10)上默认存储驱动是devicemapper 的loop-lvm模式,这种模式是用文件模拟块设备,不推荐生产使用direct lvm又不 ...

  4. Oracle 11g RAC运维总结

    转至:https://blog.csdn.net/qq_41944882/article/details/103560879 1 术语解释1.1 高可用(HA)什么是高可用?顾名思义我们能轻松地理解是 ...

  5. 哈工大 计算机网络 实验二 可靠数据传输协议(停等协议与GBN协议)

    计算机网络实验代码与文件可见github:计算机网络实验整理 实验名称 可靠数据传输协议(停等协议与GBN协议) 实验目的: 本次实验的主要目的. 理解可靠数据传输的基本原理:掌握停等协议的工作原理: ...

  6. QT:中文字符串与“常量中有字符串”报错

    解决方法参照: (10条消息) Qt5.9 win7系统 中文字符串报错:常量中有字符串_Be busy living or busy dying-CSDN博客 主要是用QStringLiteral( ...

  7. k8s全方位监控 -prometheus实现短信告警接口编写(python)

    1.prometheus短信告警接口实现(python)源码如下: import subprocess from flask import Flask from flask import reques ...

  8. (第一章第六部分)TensorFlow框架之实现线性回归小案例

    系列博客链接: (一)TensorFlow框架介绍:https://www.cnblogs.com/kongweisi/p/11038395.html (二)TensorFlow框架之图与Tensor ...

  9. LeetCode-016-最接近的三数之和

    最接近的三数之和 题目描述:给定一个包括 n 个整数的数组 nums 和 一个目标值 target.找出 nums 中的三个整数,使得它们的和与 target 最接近.返回这三个数的和.假定每组输入只 ...

  10. Comparator.comparing排序使用示例

    Comparator.comparing排序使用示例 目录 Comparator.comparing排序使用示例 背景 实体类 示例一 示例二 背景 以前常用的排序方式是通过实现Comparator接 ...