RabbitMQ HelloWorld
介绍
RabbitMQ 是一个消息队列 : 他接收和转发消息 . 我们可以把他看做邮局,当您要发布的邮件放到邮箱时,我们只要确定邮件发送给哪个收件人,然后最终 RabbitMQ 会将邮件发送给收件人,而 RabbitMQ 就相当于一个邮箱,邮局和邮递员.与邮局的区别在于,邮局处理的是纸张, 而 RabbitMQ 处理的是二进制的 Blob 数据 - 消息.
术语
Procecing 意味着仅仅是发送, 一个发送消息的程序就是一个生产者.
Queue : 队列是 RabbitMQ 中的一个"邮箱"的名字,消息只能存储在队列中,它的本质是一个大的消息缓冲区,许多生产者可以发送到一个队列的消息, 并且许多消费者可以尝试从一个队列接收数据.
Consuming 意思和接收相似, 一个消费者就是一个程序主要用来等待接收信息.
Hello World
生产者
步骤
- 导入 jar 包
- amqp-client-5.6.0.jar
- slf4j-api-1.7.26.jar
- slf4j-simple-1.7.26.jar
- 编写 Producer.java
package com.fly.rabbimq.producer;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* 生产者
*
* @author 李凡宇
*
*/
public class Producer {
// 1.声明队列的名字
public final static String QUEUE = "hello";
public static void main(String[] args) {
// 2.创建一个与服务器交互的连接
// 2-1.创建与服务器交互的连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2-2.设置服务器的地址
factory.setHost("localhost");
Connection connection = null;
Channel channel = null;
try {
// 2-3.在工厂中获得一个连接
connection = factory.newConnection();
// 2-4.在连接中获得一个通道
channel = connection.createChannel();
// 2-5.声明队列
/**
* 声明队列,如果Rabbit中没有此队列将自动创建
* param1:队列名称
* param2:是否持久化
* param3:队列是否独占此连接
* param4:队列不再使用时是否自动删除此队列
* param5:队列参数
*/
channel.queueDeclare(QUEUE, false, false, false, null);
// 2-6.要发送的消息
String message = "hello world";
// 2-7.进行发布
/**
* 消息发布方法
* param1:Exchange的名称,如果没有指定,则使用Default Exchange
* param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
* param3:消息包含的属性
* param4:消息体
* 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定
* 默认的交换机,routingKey等于队列名称
*/
channel.basicPublish("", QUEUE, null, message.getBytes());
System.out.println("send : "+ message);
} catch (Exception e) {
e.printStackTrace();
} finally{
if(channel != null){
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
- 启动 RabbitMQ 的 server 端
- 运行 Producer 文件
- 观察队列
消费者
步骤
- 导入 jar 包
- amqp-client-5.6.0.jar
- slf4j-api-1.7.26.jar
- slf4j-simple-1.7.26.jar
- 编写 Receive.java
package com.fly.rabbitmq.consumer;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;
/**
* 消费者
*
* @author 李凡宇
*
*/
public class Consumer {
// 1.声明队列的名字
public final static String QUEUE = "hello";
public static void main(String[] args) {
// 2.创建一个与服务器交互的连接
// 2-1.创建与服务器交互的连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2-2.设置服务器的地址
factory.setHost("127.0.0.1");
Connection connection = null;
Channel channel = null;
try {
connection = factory.newConnection();
channel = connection.createChannel();
// 2-3.声明队列
channel.queueDeclare(QUEUE, false, false, false, null);
// 2-4.定义消费方法
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties,
byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
//消息id
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String msg = new String(body);
System.out.println("receive message.." + msg);
}
};
// 2-5.监听队列
/**
* 监听队列String queue, boolean autoAck,Consumer callback
* 参数明细
* 1、队列名称
* 2、是否自动回复,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手 动回复
* 3、消费消息的方法,消费者接收到消息后调用此方法
*/
channel.basicConsume(QUEUE,true,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
测试
先观察浏览器中准备推送的消息记录有几条,下图中有0条
启动生产者 再次观察浏览器,发现待发送的消息有一条,增加了一条
启动消费者 可以观察到又恢复成了 0 条 , 说明我们的测试成功 .
注意
编写过程中要保证生产者与消费者的 QUEUE 的声明保持一致,否则会出现 406 错误 .
即 :
//二者要保持一致
Producer :
channel.queueDeclare(QUEUE, false, false, false, null);
Consumer :
channel.queueDeclare(QUEUE, false, false, false, null);
否则会出现如下错误 :
java.io.IOException
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:129)
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:125)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:147)
at com.rabbitmq.client.impl.ChannelN.queueDeclare(ChannelN.java:962)
at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.queueDeclare(AutorecoveringChannel.java:333)
at com.fly.rabbitmq.consumer.Consumer.main(Consumer.java:37)
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - inequivalent arg 'durable' for queue 'hello' in vhost '/': received 'true' but current is 'false', class-id=50, method-id=10)
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66)
at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36)
at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:502)
at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:293)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:141)
... 3 more
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - inequivalent arg 'durable' for queue 'hello' in vhost '/': received 'true' but current is 'false', class-id=50, method-id=10)
at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:516)
at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:346)
at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:182)
at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:114)
at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:672)
at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:48)
at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:599)
at java.lang.Thread.run(Unknown Source)