1.队列: 一端存储从另一端获取
2.堆 : 存取都在一端执行
3.rabbitMq使用场景:
- 服务解耦:rabbitMQ是一个中间件。用于将消息全部存储在消息中间件中,同时也为程序服务解耦,降低了耦合性。
- 流量削峰:当在某一间隔大量的客户进行访问服务器,中间件将会将发送的请求放在队列中慢慢的进行处理,这样把处理时间拉长,以减轻随见压力。
- 异步调用:当在高峰期,若在队列执行后返回会比较耗时,则需要引入消息队列,请求数据可以发送到消息队列,调用另一个系统先响应给用户,然后消息队列再慢慢的执行,执行最终结果再次响应给用户(客户端)。
rabbitMQ安装与运行
- 搜索官网 下载rabbitMQ:下载rmp文件
- 也可以先现在到windows系统中:通过命令brew install rabbitmq安装时下载Rabbitmq-server-generic-unix-3.8.3.tar.xz失败?当前文件可通过添加〜/ Library / Caches / Homebrew / downloads目录下,再次运行命令即可安装成功!
- (若不能执行时安装) RabbitMQ依赖于 Erlang 语言库,必须先安装Erlang语言包Erlang-R16B-03.18
- 传入到指定目录:进入目录
cd rabbitmq-in... - 安装所有的rpm文件:
rpm -ivh * .rpm
**启动rabbitmq服务器:**
1.设置服务,开机自动启动:`systemctl enable rabbitmq-server `
2.启动服务: `systemctl start rabbitmq-server`
**rabbitmq管理界面**
1.开启管理界面插件: `rabbitmq-plugins enable rabbitmq_management`
2.开启防火墙 打开一个管理端口
如: 15672 :为管理端口 5672:通信端口
1.`firewall-cmd --zone=public --add-port=15672/tcp --permanent`
2.重启`firewall-cmd --reload`
**重启rabbitmq管理界面**
systemctl restart rabbitmq-server
- 若进行访问的话,查看linux的ip :
ip addr /ipconfig
**访问管理端口**
ip:15762(管理Port)
- linux添加超级管理员
1.添加用户
rabbitmqctl add_user admin admin
2.新用户设置用户超级管理员
rabbitmqctl set_user_tags admin administrator
- 开放客户端连接端口
打开客户端间接端口
1.firewall-cmmd --zone=public --add-port=5672/tcp --permanent
2.firewall-cmd --reload
4369 – erlang发现口
5672 – client端通信口
15672 – 管理界面ui端口
25672 – server间内部通信口
设计模式(发送消息称为生产者 ,接收消息称为消费者)
使用:
- 环境:STS/IDEA +maven /springBoot +rabbitmq
2.使用时需要使用rabbitmq 依赖,及发布依赖 (若使用其他还可以添加 里面加入了日志slf4j 依赖)
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tedu</groupId>
<artifactId>rabbitmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.4.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.8.0-alpha2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.8.0-alpha2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
1. 简单模式
简单理解(一对一): rabbitmq是一个中间件,把他比作一个邮箱:一人传递 一人接收。 简单模式中一人只可以仅有一个接受者(等同于此邮箱是个人专有。)
案例:
发送创建流程: 连接 --建立管道,设置队列----发送
接受创建流程: 连接 --建立管道,设置队列----接受
区别:连接 ,建立管道使用方法一致 :
1.创建连接的工厂: new ConnectionFactory();
2.设置连接的ip,端口,用户名,密码
setHost(); //ip
setPort();//端口号
setUsername();//管理员
setPassword();//密码
3.建立管道
Connection c= 创建连接工厂引用.newConnection().createChannel();
4.创建队列
建立管道的引用.queueDeclare("队列名称",是(true)否(false)持久化,是(true)否排他(独占),断开后是(true)否(false)删除队列,其他参数若无则填null);
5.接受和发送的差异主要存在与方法
发送:
建立管道引用.basicPublish("填写交换机 默认写:空字符串" , "队列用户名",其他参数如:头信息 若无则null,消息内容.getBytes());
接受:(需要创建回调对象)
1.收到消息后处理消息的回调对象
DeliverCallback callback = new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
String msg = new String(message.getBody(), "UTF-8");
System.out.println("收到: "+msg);
}
};
2.取消消息回调对象
CancelCallback cancel = new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
};
建立管道引用.basicConsume("队列名称",是(false)否(true)手动ACK消息回执,处理消息对象DeliverCallback ,取消消息回调对象CancelCallback );
6.关闭通道
建立管道引用.close()。
发送
package rabbitmq.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Test1 {
public static void main(String[] args) throws Exception {
//创建连接工厂,并设置连接信息
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140"); //此处是远程调用linux端口
f.setPort(5672);//可选,5672是默认端口
f.setUsername("admin"); //用户名
f.setPassword("admin");
/*
* 与rabbitmq服务器建立连接,
* rabbitmq服务器端使用的是nio,会复用tcp连接,
* 并开辟多个信道与客户端通信
* 以减轻服务器端建立连接的开销
*/
//建立通信管道
Channel c=f.newConnection().createChannel();
//Connection c = f.newConnection();
//建立信道
//Channel ch = c.createChannel();
/*
* 声明队列,会在rabbitmq中创建一个队列
* 如果已经创建过该队列,就不能再使用其他参数来创建
*
* 参数含义:
* -queue: 队列名称
* -durable: 队列持久化,true表示RabbitMQ重启后队列仍存在
* -exclusive: 排他,true表示限制仅当前连接可用
* -autoDelete: 当最后一个消费者断开后,是否删除队列
* -arguments: 其他参数
*/
// ch.queueDeclare("helloworld", false,false,false,null);
//若存在直接使用,不存在则会创建
c.queueDeclare("helloword",//消息队列名称
false, //是否是持久队列
false,//是否消费者独占队列 ,false可以共享的队列
false,//是否自动删除队列(没有消费者自动删除)
null);//其他参数属性
/*
* 发布消息
* 这里把消息向默认交换机发送.
* 默认交换机隐含与所有队列绑定,routing key即为队列名称
*
* 参数含义:
* -exchange: 交换机名称,空串表示默认交换机"(AMQP default)",不能用 null
* -routingKey: 对于默认交换机,路由键就是目标队列名称
* -props: 其他参数,例如头信息
* -body: 消息内容byte[]数组
*/
ch.basicPublish("", "helloworld", null, "Hello world!".getBytes());
System.out.println("消息已发送");
c.close(); //关闭
}
}
接受
package rabbitmq.simple;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmq.client.Delivery;
public class Test2 {
public static void main(String[] args) throws Exception {
//连接工厂
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
//此处端口默认 :5672属于默认端口
f.setUsername("admin");
f.setPassword("admin");
//此处可以合并
//建立连接
Connection c = f.newConnection();
//建立信道
Channel ch = c.createChannel();
//声明队列,如果该队列已经创建过,则不会重复创建
ch.queueDeclare("helloworld",false,false,false,null);
System.out.println("等待接收数据");
//收到消息后用来处理消息的回调对象
DeliverCallback callback = new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
String msg = new String(message.getBody(), "UTF-8");
System.out.println("收到: "+msg);
}
};
//消费者取消时的回调对象
CancelCallback cancel = new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
};
ch.basicConsume("helloworld", true, callback, cancel);
}
}
2. 工作模式
思想是避免立即执行资源密集型任务

介绍(一对多):1.多个消费者可以在同一个队列中接受数据。
2. 负载均衡:轮询发送
3. 手动设置ack消息回执,可以知道消费者是空闲还是繁忙
4. 可以设置抓取消息数量 (结合手动Ack使用)
5. 消息的持久化

案例
发生的改变:具体的观看简单模式
在简单模式添加的操作:
1.为了防止消费者挂掉,而导致的数据丢失。 -----手动ACK(系统默认手动ack :false),不通过消费者发送ack给rabbitmq服务器,可以删除此消息。
2.添加消息持久化,队列持久化(在发送的头信息上加入)
3.添加每次抓取信息
修改:
发送:
1.队列持久化:
//第二个参数设置队列持久化
ch.queueDeclare("task_queue", true,false,false,null);
2. 消息持久化
//第三个参数设置消息持久化
ch.basicPublish("", "task_queue", MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes("UTF-8"));
接受:
1.队列持久化:
//第二个参数设置队列持久化
ch.queueDeclare("task_queue",true,false,false,null);
2.一次抓取一条信息
ch.basicQos(1); //一次只接收一条消息
3.在处理回调函数添加
//发送回执
ch.basicAck(message.getEnvelope().getDeliveryTag(), false);
4.手动ack
//autoAck设置为false,则需要手动确认发送回执
ch.basicConsume("task_queue", false, callback, cancel);
发送
package rabbitmq.workqueue;
import java.util.Scanner;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
public class Test3 {
public static void main(String[] args) throws Exception {
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setPort(5672);
f.setUsername("admin");
f.setPassword("admin");
Connection c = f.newConnection();
Channel ch = c.createChannel();
//第二个参数设置队列持久化
ch.queueDeclare("task_queue", true,false,false,null);
while (true) {
System.out.print("输入消息: ");
String msg = new Scanner(System.in).nextLine();
if ("exit".equals(msg)) {
break;
}
//第三个参数设置消息持久化
ch.basicPublish("", "task_queue", MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes("UTF-8"));
System.out.println("消息已发送: "+msg);
}
c.close();
}
}
接受
package rabbitmq.workqueue;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmq.client.Delivery;
public class Test4 {
public static void main(String[] args) throws Exception {
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setUsername("admin");
f.setPassword("admin");
Connection c = f.newConnection();
Channel ch = c.createChannel();
//第二个参数设置队列持久化
ch.queueDeclare("task_queue",true,false,false,null);
System.out.println("等待接收数据");
ch.basicQos(1); //一次只接收一条消息
//收到消息后用来处理消息的回调对象
DeliverCallback callback = new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
String msg = new String(message.getBody(), "UTF-8");
System.out.println("收到: "+msg);
for (int i = 0; i < msg.length(); i++) {
if (msg.charAt(i)=='.') {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
System.out.println("处理结束");
//发送回执
ch.basicAck(message.getEnvelope().getDeliveryTag(), false);
}
};
//消费者取消时的回调对象
CancelCallback cancel = new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
};
//autoAck设置为false,则需要手动确认发送回执
ch.basicConsume("task_queue", false, callback, cancel);
}
}
3. 发布和订阅模式
RabbitMQ消息传递模型的核心思想是,生产者永远不会将任何消息直接发送到队列。实际上,通常生产者甚至不知道消息是否会被传递到任何队列。

介绍: 1. 等同于群发:一条消息,可以多个消费者收到。
2.fanout类型交换机:将接受到的所有消息广播给它所知道的所有队列 ,作用可以做日志系统。
何为交换机:交换机可以一边接受一边将消息推送到队列(常见交换机:direct,topic,header,fanout)
3. 你要明白这里会需要不同的队列来接收。

案例
1.更换交换机,不使用系统默认的,发布订阅使用fandout
2.为了演示 :创建非持久的、独占的、自动删除队列
3.增加了绑定
发送
package rabbitmq.publishsubscribe;
import java.util.Scanner;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Test1 {
public static void main(String[] args) throws Exception {
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setPort(5672);
f.setUsername("admin");
f.setPassword("admin");
Connection c = f.newConnection();
Channel ch = c.createChannel();
//定义名字为logs的交换机,交换机类型为fanout
//这一步是必须的,因为禁止发布到不存在的交换。
ch.exchangeDeclare("logs", "fanout"); //定义交换机名称
//或者使用:
//ch.exchangeDeclare("logs", BuiltinExchangeType.FANOUT);
while (true) {
System.out.print("输入消息: ");
String msg = new Scanner(System.in).nextLine();
if ("exit".equals(msg)) {
break;
}
//第一个参数,向指定的交换机发送消息
//第二个参数,不指定队列,由消费者向交换机绑定队列
//如果还没有队列绑定到交换器,消息就会丢失,
//但这对我们来说没有问题;即使没有消费者接收,我们也可以安全地丢弃这些信息。
ch.basicPublish("logs", "", null, msg.getBytes("UTF-8"));
System.out.println("消息已发送: "+msg);
}
c.close();
}
}
接受
package rabbitmq.publishsubscribe;
import java.io.IOException;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmq.client.Delivery;
public class Test2 {
public static void main(String[] args) throws Exception {
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setUsername("admin");
f.setPassword("admin");
Connection c = f.newConnection();
Channel ch = c.createChannel();
//定义名字为 logs 的交换机, 它的类型是 fanout
ch.exchangeDeclare("logs", "fanout");
//或者
//或者使用:
//ch.exchangeDeclare("logs", BuiltinExchangeType.FANOUT);
//自动生成对列名,
//非持久,独占,自动删除
String queueName = ch.queueDeclare().getQueue();//服务器随机命名
//等同于
//String queue= UUID.randomUUID().toString(); //调用UUID随机生成
// ch.queueDeclare(queue,false,true,true,null);//为了演示设置了,非持久化,独占,自动删除序列
//把该队列,绑定到 logs 交换机
//对于 fanout 类型的交换机, routingKey会被忽略,不允许null值
ch.queueBind(queueName, "logs", "");
System.out.println("等待接收数据");
//收到消息后用来处理消息的回调对象
DeliverCallback callback = new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
String msg = new String(message.getBody(), "UTF-8");
System.out.println("收到: "+msg);
}
};
//消费者取消时的回调对象
CancelCallback cancel = new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
};
ch.basicConsume(queueName, true, callback, cancel);
}
}
4. 路由模式
介绍:根据队列的名称,指定发送到队列。


案例
1.需要绑定,需要使用routingKey参数,取决于交换机名字
2.使用直连交换机 DIrect
发送
package rabbitmq.routing;
import java.util.Random;
import java.util.Scanner;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Test1 {
public static void main(String[] args) throws Exception {
String[] a = {"warning", "info", "error"};
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setPort(5672);
f.setUsername("admin");
f.setPassword("admin");
Connection c = f.newConnection();
Channel ch = c.createChannel();
//参数1: 交换机名
//参数2: 交换机类型
ch.exchangeDeclare("direct_logs", BuiltinExchangeType.DIRECT);
while (true) {
System.out.print("输入消息: ");
String msg = new Scanner(System.in).nextLine();
if ("exit".equals(msg)) {
break;
}
//随机产生日志级别
String level = a[new Random().nextInt(a.length)];
//参数1: 交换机名
//参数2: routingKey, 路由键,这里我们用日志级别,如"error","info","warning"
//参数3: 其他配置属性
//参数4: 发布的消息数据
ch.basicPublish("direct_logs", level, null, msg.getBytes());//名称,路右键,其他配置,发布信息数据
System.out.println("消息已发送: "+level+" - "+msg);
}
c.close();
}
}
接受
package rabbitmq.routing;
import java.io.IOException;
import java.util.Scanner;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmq.client.Delivery;
public class Test2 {
public static void main(String[] args) throws Exception {
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setUsername("admin");
f.setPassword("admin");
Connection c = f.newConnection();
Channel ch = c.createChannel();
//定义名字为 direct_logs 的交换机, 它的类型是 "direct"
ch.exchangeDeclare("direct_logs", BuiltinExchangeType.DIRECT);
//自动生成对列名,
//非持久,独占,自动删除
String queueName = ch.queueDeclare().getQueue();
System.out.println("输入接收的日志级别,用空格隔开:");
String[] a = new Scanner(System.in).nextLine().split("\\s");//填写所向队列传递,名称
//把该队列,绑定到 direct_logs 交换机
//允许使用多个 bindingKey
for (String level : a) {
ch.queueBind(queueName, "direct_logs", level);
}
System.out.println("等待接收数据");
//收到消息后用来处理消息的回调对象
DeliverCallback callback = new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
String msg = new String(message.getBody(), "UTF-8");
String routingKey = message.getEnvelope().getRoutingKey();//随机生成名称
System.out.println("收到: "+routingKey+" - "+msg);
}
};
//消费者取消时的回调对象
CancelCallback cancel = new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
}
};
ch.basicConsume(queueName, true, callback, cancel);
}
}
5. 主题模式
6. RPC模式

1774

被折叠的 条评论
为什么被折叠?



