目录
1. 安装Socat
yum install gcc
yum install socat
yum install openssl
yum install openssl-devel
2. 安装Erlang
mkdir /rabbitmq
cd /rabbitmq
# 上传 erlang-22.0.7-1.el7.x86_64.rpm 安装包上传
# 安装
rpm -ivh erlang-22.0.7-1.el7.x86_64.rpm
3. 安装RabbitMQ
cd /rabbitmq
# 上传 rabbitmq-server-3.7.17-1.el7.noarch.rpm 安装包
上传# 安装
rpm -ivh rabbitmq-server-3.7.17-1.el7.noarch.rpm
4. 开启管理界面及配置
# 开启管理界面
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
配置文件:
5. 启动
centos6用这个命令:
/sbin/service rabbitmq-server restartcentos7用这个命令:
systemctl start rabbitmq-server
6. 配置虚拟主机及用户
6.1. 用户角色
RabbitMQ在安装好后,可以访问http://ip地址:15672
;其自带了guest/guest的用户名和密码;如果需要创建自定义用户;那么也可以登录管理界面后,如下操作:
角色说明:
1、 超级管理员(administrator)
可登陆管理控制台,可查看所有的信息,并且可以对用户,策略(policy)进行操作。
2、 监控者(monitoring)
可登陆管理控制台,同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)
3、 策略制定者(policymaker)
可登陆管理控制台, 同时可以对policy进行管理。但无法查看节点的相关信息(上图红框标识的部分)。
4、 普通管理者(management)
仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理。
5、 其他
无法登陆管理控制台,通常就是普通的生产者和消费者。
6.2. Virtual Hosts配置
像mysql拥有数据库的概念并且可以指定用户对库和表等操作的权限。RabbitMQ也有类似的权限管理;在RabbitMQ中可以虚拟消息服务器Virtual Host,每个Virtual Hosts相当于一个相对独立的RabbitMQ服务器,每个VirtualHost之间是相互隔离的。exchange、queue、message不能互通。 相当于mysql的db。Virtual Name一般以/开头。
6.2.1. 创建Virtual Hosts
6.2.2. 设置Virtual Hosts权限
7.RabbitMQ消息中间件
7.1 什么MQ?
MQ全称 Message Queue(消息队列),是在消息的传输过程中保存 消息的容器。多用于分布式系统之间进行通信。
思考: 原来服务与服务之间如何通信?
Openfeign 服务与服务之间直接调用。
我们也可以使用MQ完成系统与系统之间得调用。
7.2 MQ优点
1. 应用解耦
2. 异步提速
3. 削锋填谷
![]()
7.3 MQ缺点
7.4 如何选择MQ.
7.5 MQ得种类
rabbitMQ
kafka
RocketMQ
ActiveMQ
7.6 RabbitMQ
安装RabbitMQ 略
7.7 概述端口号
7.8 rabbit的工作原理
7.9 java程序连接RabbitMQ服务
提供了5种模式。
1. 简单模式--Hello
2. 工作者模式--work queues
![]()
3. 发布订阅模式
![]()
4. 路由模式--router
![]()
5. 主题模式--topic
![]()
7.9.1 simple 简单模式
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.14.2</version>
</dependency>
</dependencies>
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<String, Object> 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);
}
}
注:不要关闭连接对象
7.9.2 woker模式
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<String, Object> 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--和上面的消费者相同。
7.9.3 public/Subscribe发布订阅模式
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<String, Object> 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);
}
}
7.9.4 router路由模式
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<String, Object> 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);
}
}
7.9.5 主题模式--topic
*: 统配一个单词
: 统配零个或者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<String, Object> 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);
}
}
7.10 springboot整合rabbitMQ
(1)生产者的代码
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置文件
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("保存订单到数据库");
Map<String,Object> map=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(Map<String,Object> msg){
System.out.println(msg);
//进行相关的业务处理
}
}