目录
1. 安装Socat
2. 安装Erlang
3. 安装RabbitMQ
4. 开启管理界面及配置
5. 启动
6. 配置虚拟主机及用户
6.1. 用户角色
6.2. Virtual Hosts配置
6.2.1. 创建Virtual Hosts
6.2.2. 设置Virtual Hosts权限
7.RabbitMQ消息中间件
7.1 什么MQ?
7.2 MQ优点
7.3 MQ缺点
7.4 如何选择MQ.
7.5 MQ得种类
7.6 RabbitMQ
7.7 概述端口号
7.8 rabbit的工作原理
7.9 java程序连接RabbitMQ服务
7.9.1 simple 简单模式
7.9.2 woker模式
7.9.3 public/Subscribe发布订阅模式
7.9.4 router路由模式
7.9.5 主题模式--topic
7.10 springboot整合rabbitMQ
yum install gcc
yum install socat
yum install openssl
yum install openssl-devel
mkdir /rabbitmq
cd /rabbitmq
# 上传 erlang-22.0.7-1.el7.x86_64.rpm 安装包上传
# 安装
rpm -ivh erlang-22.0.7-1.el7.x86_64.rpm
cd /rabbitmq
# 上传 rabbitmq-server-3.7.17-1.el7.noarch.rpm 安装包
上传# 安装
rpm -ivh rabbitmq-server-3.7.17-1.el7.noarch.rpm
# 开启管理界面
rabbitmq-plugins enable rabbitmq_management# 配置远程可使用guest登录mq
cd /usr/share/doc/rabbitmq-server-3.7.17cp rabbitmq.config.example /etc/rabbitmq/rabbitmq.config
# 修改配置文件
vi /etc/rabbitmq/rabbitmq.config
修改/etc/rabbitmq/rabbitmq.config
配置文件:
centos6用这个命令:
/sbin/service rabbitmq-server restartcentos7用这个命令:
systemctl start rabbitmq-server
RabbitMQ在安装好后,可以访问http://ip地址:15672
;其自带了guest/guest的用户名和密码;如果需要创建自定义用户;那么也可以登录管理界面后,如下操作:
角色说明:
1、 超级管理员(administrator)
可登陆管理控制台,可查看所有的信息,并且可以对用户,策略(policy)进行操作。
2、 监控者(monitoring)
可登陆管理控制台,同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)
3、 策略制定者(policymaker)
可登陆管理控制台, 同时可以对policy进行管理。但无法查看节点的相关信息(上图红框标识的部分)。
4、 普通管理者(management)
仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理。
5、 其他
无法登陆管理控制台,通常就是普通的生产者和消费者。
像mysql拥有数据库的概念并且可以指定用户对库和表等操作的权限。RabbitMQ也有类似的权限管理;在RabbitMQ中可以虚拟消息服务器Virtual Host,每个Virtual Hosts相当于一个相对独立的RabbitMQ服务器,每个VirtualHost之间是相互隔离的。exchange、queue、message不能互通。 相当于mysql的db。Virtual Name一般以/开头。
MQ全称 Message Queue(消息队列),是在消息的传输过程中保存 消息的容器。多用于分布式系统之间进行通信。
思考: 原来服务与服务之间如何通信?
Openfeign 服务与服务之间直接调用。
我们也可以使用MQ完成系统与系统之间得调用。
1. 应用解耦
2. 异步提速
3. 削锋填谷
rabbitMQ
kafka
RocketMQ
ActiveMQ
安装RabbitMQ 略
提供了5种模式。
1. 简单模式--Hello
2. 工作者模式--work queues
3. 发布订阅模式
4. 路由模式--router
5. 主题模式--topic
com.rabbitmq
amqp-client
5.14.2
P: 一个生产者
C: 一个消费者
Q: 队列
代码--生产者:
package com.product.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @Author bian
* @Date 2022/9/20 19:33
* @PackageName:com.product.simple
* @ClassName: Test01
* @Description: TODO
* @Version 1.0
*/
public class Test01 {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection = factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//创建队列
/**
* 如果该队列名不存在则自动创建,存在则不创建
* String queue,队列名
* boolean durable,是否持久化
* boolean exclusive,(独占)声明队列同一时间只能保
证一个连接,且该队列只有被这一个连接使用。
* boolean autoDelete,是否自动删除
* Map arguments: 其他参数
*/
channel.queueDeclare("simple_queue", true, false, false, null);
//发送消息到队列
/**
* String exchange,把消息发给哪个交换机--简单模式没
有交换机""
* String routingKey,消息绑定的路由key 如果为简单模式 默认写为队列名称
* BasicProperties props, 消息的属性
* byte[] body: 消息的内容
*/
String msg = "hello world~~~~3";
channel.basicPublish("", "simple_queue", null, msg.getBytes());
connection.close();
}
}
代码-消费者:
package com.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @Author bian
* @Date 2022/9/20 20:01
* @PackageName:com.consumer
* @ClassName: Test02
* @Description: TODO
* @Version 1.0
*/
public class Test02 {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection = factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//监听队列
/**
* String queue,监听的队列名称
* autoAck:是否自动确认消息
* Consumer callback: 监听到消息后触发的回调函数
*/
DefaultConsumer callback = new DefaultConsumer(channel) {
//一定有消息就会触发该方法
//body:表示消息的内容
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接受的消息内容:" + new String(body));
}
};
channel.basicConsume("simple_queue", true, callback);
}
}
注:不要关闭连接对象
P:生产者
C1:消费者1
C2:消费者2
Q: 队列
消费者1和消费者2属于竞争关系,一个消息只会被一个消费者消费。
代码---生产者
package com.product.worker;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @Author bian
* @Date 2022/9/20 20:09
* @PackageName:com.product.worker
* @ClassName: TestWork01
* @Description: TODO
* @Version 1.0
*/
public class TestWork01 {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection = factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//创建队列
/**
* 如果该队列名不存在则自动创建,存在则不创建
* String queue,队列名
* boolean durable,是否持久化
* boolean exclusive,(独占)声明队列同一时间只能保
证一个连接,且该队列只有被这一个连接使用。
* boolean autoDelete,是否自动删除
* Map arguments: 其他参数
*/
channel.queueDeclare("worker_queue", true, false, false, null);
//发送消息到队列
/**
* String exchange,把消息发给哪个交换机--简单模式没
有交换机""
* String routingKey,消息绑定的路由key 如果为简单模式 默认写为队列名称
* BasicProperties props, 消息的属性
* byte[] body: 消息的内容
*/
for (int i = 0; i < 10; i++) {
String msg = "Worker msg=======" + i;
channel.basicPublish("", "worker_queue", null, msg.getBytes());
}
connection.close();
}
}
代码--消费01
package com.consumer.worker;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @Author bian
* @Date 2022/9/20 20:13
* @PackageName:com.consumer.worker
* @ClassName: WorkerConsumer01
* @Description: TODO
* @Version 1.0
*/
public class WorkerConsumer01 {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection = factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//监听队列
/**
* String queue,监听的队列名称
* autoAck:是否自动确认消息
* Consumer callback: 监听到消息后触发的回调函数
*/
DefaultConsumer callback = new DefaultConsumer(channel) {
//一定有消息就会触发该方法
//body:表示消息的内容
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接受的消息内容:" + new String(body));
}
};
channel.basicConsume("worker_queue", true, callback);
}
}
代码--消费者02--和上面的消费者相同。
p: producter 生产者
x:exchange交换机
Q: 队列
C1和C2:消费者
生产者--代码
package com.product.publish;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @Author bian
* @Date 2022/9/20 20:18
* @PackageName:com.product.publish
* @ClassName: TestPublisher
* @Description: TODO
* @Version 1.0
*/
public class TestPublisher {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection = factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//创建队列
/**
* 如果该队列名不存在则自动创建,存在则不创建
* String queue,队列名
* boolean durable,是否持久化
* boolean exclusive,(独占)声明队列同一时间只能保证一个连接,且该队列只有被这一个连接使用。
* boolean autoDelete,是否自动删除
* Map arguments: 其他参数
*/
channel.queueDeclare("publisher_queue01", true, false, false, null);
channel.queueDeclare("publisher_queue02", true, false, false, null);
//创建交换机
/*
String exchange,交换机的名称
BuiltinExchangeType type,交换机的种类
boolean durable:是否持久化
*/
channel.exchangeDeclare("fanout_exchange", BuiltinExchangeType.FANOUT, true);
//交换机和队列绑定
/*
String queue,队列名 String exchange,交换机名
String routingKey 路由key 如果为发布订阅模式则无需路由key
*/
channel.queueBind("publisher_queue01", "fanout_exchange", "");
channel.queueBind("publisher_queue02", "fanout_exchange", "");
//发送消息到队列
/**
* String exchange,把消息发给哪个交换机--简单模式没有交换机""
* String routingKey,消息绑定的路由key 如果为简单模式 默认写为队列名称
* BasicProperties props, 消息的属性
* byte[] body: 消息的内容
*/
for (int i = 0; i < 10; i++) {
String msg = "publisher msg=======" + i;
channel.basicPublish("fanout_exchange",
"", null, msg.getBytes());
}
connection.close();
}
}
消费者--01
package com.consumer.pubisher;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @Author bian
* @Date 2022/9/20 20:23
* @PackageName:com.consumer.pubisher
* @ClassName: PublisherConsumer01
* @Description: TODO
* @Version 1.0
*/
public class PublisherConsumer01 {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection = factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//监听队列
/**
* String queue,监听的队列名称
* autoAck:是否自动确认消息
* Consumer callback: 监听到消息后触发的回调函数
*/
DefaultConsumer callback = new DefaultConsumer(channel) {
//一定有消息就会触发该方法
//body:表示消息的内容
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接受的消息内容:" + new String(body));
}
};
channel.basicConsume("publisher_queue01", true, callback);
}
}
p:生产者
x: 交换机---Direct (路由模式)
c1和c2表示消费者:
Q:队列
package com.product.routing;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @Author bian
* @Date 2022/9/20 20:27
* @PackageName:com.product.routing
* @ClassName: TestRouter
* @Description: TODO
* @Version 1.0
*/
public class TestRouter {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection = factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//创建队列
/**
* 如果该队列名不存在则自动创建,存在则不创建
* String queue,队列名
* boolean durable,是否持久化
* boolean exclusive,(独占)声明队列同一时间只能保证一个连接,且该队列只有被这一个连接使用。
* boolean autoDelete,是否自动删除
* Map arguments: 其他参数
*/
channel.queueDeclare("router_queue01", true, false, false, null);
channel.queueDeclare("router_queue02", true, false, false, null);
//创建交换机
/*
String exchange,交换机的名称
BuiltinExchangeType type,交换机的种类
boolean durable:是否持久化
*/
channel.exchangeDeclare("direct_exchange", BuiltinExchangeType.DIRECT, true);
//交换机和队列绑定
/*
String queue,队列名 String exchange,交换机名 String routingKey 路由key 如果为发布订阅模式则无需路由key
*/
channel.queueBind("router_queue01", "direct_exchange", "error");
channel.queueBind("router_queue02", "direct_exchange", "error");
channel.queueBind("router_queue02", "direct_exchange", "info");
channel.queueBind("router_queue02", "direct_exchange", "warning");
//发送消息到队列
/**
* String exchange,把消息发给哪个交换机--简单模式没有交换机""
* String routingKey,消息绑定的路由key 如果为简单模式 默认写为队列名称
* BasicProperties props, 消息的属性
* byte[] body: 消息的内容
*/
String msg = "publisher msg=======2";
channel.basicPublish("direct_exchange", "info", null, msg.getBytes());
connection.close();
}
}
消费者01-代码
package com.consumer.routing;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @Author bian
* @Date 2022/9/20 20:29
* @PackageName:com.consumer.routing
* @ClassName: RouterConsumer01
* @Description: TODO
* @Version 1.0
*/
public class RouterConsumer01 {
public static void main(String[] args) throws Exception {
ConnectionFactory factory=new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection=factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//监听队列
/**
* String queue,监听的队列名称
* autoAck:是否自动确认消息
* Consumer callback: 监听到消息后触发的回调函数
*/
DefaultConsumer callback=new DefaultConsumer(channel){
//一定有消息就会触发该方法
//body:表示消息的内容
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接受的消息内容:"+new String(body));
}
};
channel.basicConsume("router_queue01",true,callback);
}
}
*: 统配一个单词
: 统配零个或者n个单词
生产者代码
package com.product.topic;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @Author bian
* @Date 2022/9/20 20:31
* @PackageName:com.product.topic
* @ClassName: TestTopic
* @Description: TODO
* @Version 1.0
*/
public class TestTopic {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection = factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//创建队列
/**
* 如果该队列名不存在则自动创建,存在则不创建
* String queue,队列名
* boolean durable,是否持久化
* boolean exclusive,(独占)声明队列同一时间只能保证一个连接,且该队列只有被这一个连接使用。
* boolean autoDelete,是否自动删除
* Map arguments: 其他参数
*/
channel.queueDeclare("topic_queue01", true, false, false, null);
channel.queueDeclare("topic_queue02", true, false, false, null);
//创建交换机
/*
String exchange,交换机的名称
BuiltinExchangeType type,交换机的种类
boolean durable:是否持久化
*/
channel.exchangeDeclare("topic_exchange", BuiltinExchangeType.TOPIC, true);
//交换机和队列绑定
/*
String queue,队列名 String exchange,交换机名 String routingKey 路由key 如果为发布订阅模式则无需路由key
*/
channel.queueBind("topic_queue01", "topic_exchange", "*.orange.*");
channel.queueBind("topic_queue02", "topic_exchange", "*.*.rabbit");
channel.queueBind("topic_queue02", "topic_exchange", "lazy.#");
//发送消息到队列
/**
* String exchange,把消息发给哪个交换机--简单模式没有交换机""
* String routingKey,消息绑定的路由key 如果为简单模式 默认写为队列名称
* BasicProperties props, 消息的属性
* byte[] body: 消息的内容
*/
String msg = "routers msg=======2";
channel.basicPublish("topic_exchange", "lazy.orange.rabbit.qy151", null, msg.getBytes());
connection.close();
}
}
消费者01:
package com.consumer.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @Author bian
* @Date 2022/9/20 20:32
* @PackageName:com.consumer.topic
* @ClassName: TopicConsumer02
* @Description: TODO
* @Version 1.0
*/
public class TopicConsumer02 {
public static void main(String[] args) throws Exception {
ConnectionFactory factory=new ConnectionFactory();
//设置rabbitMQ服务器的地址 默认localhost
factory.setHost("192.168.174.130");
//设置rabbitMQ的端口号 默认5672
factory.setPort(5672);
//设置账号和密码 默认guest
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟主机名 默认为 /
factory.setVirtualHost("/");
//获取连接通道
Connection connection=factory.newConnection();
//获取channel信道
Channel channel = connection.createChannel();
//监听队列
/**
* String queue,监听的队列名称
* autoAck:是否自动确认消息
* Consumer callback: 监听到消息后触发的回调函数
*/
DefaultConsumer callback=new DefaultConsumer(channel){
//一定有消息就会触发该方法
//body:表示消息的内容
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接受的消息内容:"+new String(body));
}
};
channel.basicConsume("topic_queue02",true,callback);
}
}
(1)生产者的代码
依赖
org.springframework.boot
spring-boot-starter-amqp
配置文件
server.port=7000
#rabbitMQ的配置
spring.rabbitmq.host=192.168.223.155
spring.rabbitmq.port=5672
#spring.rabbitmq.username=guest
#spring.rabbitmq.password=guest
#spring.rabbitmq.virtual-host=/
使用工具类发送消息到队列
@Autowired
private RabbitTemplate rabbitTemplate;
@GetMapping("saveOrder")
public void saveOrder(){
System.out.println("保存订单到数据库");
Mapmap=new HashMap<>();
map.put("orderId","110");
map.put("price",2500);
map.put("num",3);
map.put("phone","15700085997");
rabbitTemplate.convertAndSend("testX","b",map);
}
(2)消费者
package com.ykq.rabbitmq;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Map;
@Component
public class MyListener {@RabbitListener(queues = "test02")
public void test(Mapmsg){
System.out.println(msg);
//进行相关的业务处理
}
}