文章目录
Virtual Host的作用
开始之前我们先要强调一个概念 Virtual Host 。Virtual Host是什么作用呢?有什么作用呢?
在 RabbitMQ 中,Virtual Host 可以理解为Mysql 中的库名的作用。
- 用于隔离不同项目,解决命名冲突
- 用户权限分配的最小粒度
比如现在我一个公司有多个项目需要用到MQ,那么我可能在开发环境的情况下,不同项目用到的 MQ 服务器为同一台,而且不同项目之间就通过这个 Visual Host 来区分,不同的 Virtual Host 之间可以有相同的交换机或者是队列命名,并且不同 vhost 下面的 Exchange, Queue,Message 是不能互通的。(比如Mysql中 db1 和 db2 两个不同的库,都有同名的 User 表,)
RabbitMQ在给用户分配操作权限时,需要通过给用户分配在不同 vhost 的权限,但是不能分权限到Exchange或者Queue上面
rabbitmqctl.bat set_permissions -p <vhost> <username> <permissions>
创建 VHost
这里我都输入为 /HelloWorld , 可以VHost添加成功 注意一定VHost一定要加上 / ,避免之后连接报错
创建用于这个 VHost 的用户
由于之前我创建的 admin 用户是整个rabbitMq 的管理员用户,拥有的权限太高,不适合用于开发,这里我们专门来创建一个用户用于HelloWorld 这个 VHost。
这里我创建了一个 hello 用户,可以看到现在还没有该用户可以访问的VHost
那我们点击 hello 这个名字去设置该用户的权限
然后程序里面就可以用这个用户来进行消息通讯了。
创建一个 HelloWorld 队列
创建成功后如下图所示
用 Maven 搭建最基本的生产者和消费者
引入maven依赖
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.6.5 </version>
</dependency>
</dependencies>
创建连接代码
/**
* RabbitMQ 连接类,用于建立与RabbitMQ Server端的连接
* 官方文档地址:http://previous.rabbitmq.com/v3_5_7/tutorials/tutorial-one-java.html
*
*/
public class RabbitMQConnection {
public static String RABBIT_MQ_SERVER_HOST = "192.168.199.240";
public static int RABBIT_MQ_SERVER_PORT = 5672;
public static String VIRTUAL_HOST = "/HelloWorld";
/**
* 获取RabbitMQ连接
* @return
*/
public static Connection getConnection() throws IOException, TimeoutException {
//1、创建连接
ConnectionFactory factory = new ConnectionFactory();
//2、设置主机名
factory.setHost(RABBIT_MQ_SERVER_HOST);
//3、设置通讯端口,默认是5672,不专门设置也可以
//factory.setPort(RABBIT_MQ_SERVER_PORT);
//4、设置账号和密码
factory.setUsername("hello");
factory.setPassword("123456");
//4、设置Virtual Host
factory.setVirtualHost(VIRTUAL_HOST);
//5、创建连接
return factory.newConnection();
}
}
生产者代码
/**
* 生产者
*/
public class Producer {
private static final String QUEUE_NAME = "HelloWorld";
public static void main(String[] args) throws IOException, TimeoutException {
while (true) {
System.out.println("请输入消息:");
Scanner scanner = new Scanner(System.in);
//1、创建连接
Connection connection = RabbitMQConnection.getConnection();
//2、创建通道
Channel channel = connection.createChannel();
//3、发送消息,这里使用Scanner通过控制台输入的内容来作为消息
//nextLine() 以回车结束当前的输入,会接收空格
String message = scanner.nextLine();
/*
参数说明:
exchange:当期尚未指定exchange,又不能为null,只能设置为一个空字符串
routingKey: 就是队列名称
props:消息的额外属性
body: 消息主体
*/
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println("消息已被发送:" + message);
//发送完记得关闭连接
channel.close();
connection.close();
}
}
}
消费者代码
/**
* 消费者
*/
public class Consumer {
private static final String QUEUE_NAME = "HelloWorld";
public static void main(String[] args) throws IOException, TimeoutException {
// 1、创建连接
Connection connection = RabbitMQConnection.getConnection();
// 2、创建通道
Channel channel = connection.createChannel();
// 3、设置队列的消费逻辑
DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
//接收到一个消息时会使用这个方法,这里进行重写,用来输出接收到的消息
/*
参数说明:
consumerTag:消费者关联的标签
envelope: 消息包数据
BasicProperties:消息的额外属性
body: 消息主体,当前为二进制
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String messageBody = new String(body);
System.out.println("消费者消费消息:"+messageBody);
}
};
// 4、添加监听。队列需要在服务器中先创建好,不然启动会发生 NOT_FOUND - no queue 'HelloWorld'的错误
// 开启自动确认,表示当消费者一旦接收到消息,队列就会把消息删除。无论消费者之后的处理是否报错
channel.basicConsume(QUEUE_NAME,true, defaultConsumer);
}
}
不同顺序启动和执行
先启动好生产者和消费者,然后生产消息
把生产者和消费者启动后:输入消息,能被监听到
一个最基本的消息已经创建成功和消费成功了。
先启动好生产者,然后生产消息,再启动消费者
此时能够在队列里面看到有两条消息在队列中(被持久化了,因为我们创建队列的时候,选择的是默认的支持持久化的选项)
然后启动停止掉生产者,再启动消费者。发现消费会被顺序消费掉。
然后队列里面的消息个数面板又变回了0
异常问题
- 设置权限后无法登陆,报 Not management user 错误
答:因为这时候的用户权限主要是在消息通讯,主要用于生产者和消费者。并没有 management 页面的权限。因此我们可以用分配了 administrator 的 admin 用户来进行界面管理。而没有分配角色的用来处理消息通讯。
或者给 hello 用户分配角色 administrator