RabbitMQ入门:Hello RabbitMQ 代码实例
在之前的一篇博客RabbitMQ入门:认识并安装RabbitMQ(以Windows系统为例)中,我们安装了RabbitMQ并且对其也有的初步的认识,今天就来写个入门小例子来加深概念理解并了解代码怎么实现。
本篇博客围绕下面几个方面展开:
- 代码前的理论热身
- 代码实例:Hello RabbitMQ
- 运行代码并调试问题
Now, Let's begin !
一、代码前的理论热身
我们来看张图:

Publisher(生产者)生成消息,然后publish(发布)消息到exchange(路由器,也有资料翻译成交换机),然后根据路由规则将消息传递到Queue(队列),最终交由Consumer(消费者)进行消费处理。
这里的生产者和消费者都是我们的应用,因此我们的代码中要实现这两个部分。
中间的节点就是RabbitMQ 提供的内容,需要再生产者和消费者里面调用其接口来定义和使用这些节点。
二、代码实例:Hello RabbitMQ
- 首先来实现生产者,这里我没有用Publisher做类名,而是用的Provider,没有特别的用意,就是在起名字的时候不小心写成了这样,不需要在意这个细节,O(∩_∩)O。
package com.sam.hello_rabbitmq; import java.io.IOException;
import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; public class Provider { //定义队列名
static String QUEUE_NAME = "helloRabbit"; public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = null;
Channel channel = null;
try {
//1.创建连接和通道
connection = factory.newConnection();
channel = connection.createChannel(); //2.为通道声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null); //3.发布消息
String msg = " hello rabbitmq, welcome to sam's blog.";
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
System.out.println("provider send a msg: " + msg);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
//4.关闭连接
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();
}
}
} } }在第2步中,channel.queueDeclare 用来创建队列,有5个参数:String queue, 队列名; boolean durable, 该队列是否需要持久化; boolean exclusive,该队列是否为该通道独占的(其他通道是否可以消费该队列); boolean autoDelete,该队列不再使用的时候,是否让RabbitMQ服务器自动删除掉; Map<String, Object> arguments 其他参数。第3步中,channel.basicPublish 发布消息(用在生产者),有4个参数:String exchange, 路由器(有的资料翻译成交换机)的名字,即将消息发到哪个路由器; String routingKey, 路由键,即发布消息时,该消息的路由键是什么; BasicProperties props, 指定消息的基本属性; byte[] body 消息体,也就是消息的内容,是字节数组。 可能你会疑惑,为什么没有exchange呢?因为如果声明了队列,可以不声明路由器。
- 接着来实现消费者,消费者实现和生产者过程差不多,但是在这里并没有关闭连接和通道,是因为要消费者一直等待随时可能发来的消息。代码如下:
package com.sam.hello_rabbitmq; 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.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope; public class HelloConsumer { public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = null;
Channel channel = null;
try {
// 1.创建连接和通道
connection = factory.newConnection();
channel = connection.createChannel(); // 2.为通道声明队列
channel.queueDeclare(Provider.QUEUE_NAME, false, false, false, null);
System.out.println(" **** keep alive ,waiting for messages, and then deal them");
// 3.通过回调生成消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
com.rabbitmq.client.AMQP.BasicProperties properties, byte[] body) throws IOException { //获取消息内容然后处理
String msg = new String(body, "UTF-8");
System.out.println("*********** HelloConsumer" + " get message :[" + msg +"]");
}
}; //4.消费消息
channel.basicConsume(Provider.QUEUE_NAME, true, consumer); } catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}在第4步中,channel.basicConsume 用来接收消息,用在消费者,有3个参数:String queue, 队列名字,即要从哪个队列中接收消息; boolean autoAck, 是否自动确认,默认true; Consumer callback 消费者,即谁接收消息。
三、运行代码并调试问题
代码写好了,接下来进行测试,
- 先来执行下Provider.java,发现报错了:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
java.io.IOException
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:124)
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:120)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:142)
at com.rabbitmq.client.impl.ChannelN.queueDeclare(ChannelN.java:952)
at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.queueDeclare(AutorecoveringChannel.java:333)
at com.sam.hello_rabbitmq.Provider.main(Provider.java:36)
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 'helloRabbit' in vhost '/': received 'false' but current is 'true', 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:443)
at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:263)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:136)
... 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 'helloRabbit' in vhost '/': received 'false' but current is 'true', class-id=50, method-id=10)
at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:509)
at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:340)
at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:162)
at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:109)
at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:643)
at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47)
at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:581)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "main" com.rabbitmq.client.AlreadyClosedException: channel is already closed due to channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - inequivalent arg 'durable' for queue 'helloRabbit' in vhost '/': received 'false' but current is 'true', class-id=50, method-id=10)
at com.rabbitmq.client.impl.AMQChannel.processShutdownSignal(AMQChannel.java:345)
at com.rabbitmq.client.impl.ChannelN.startProcessShutdownSignal(ChannelN.java:286)
at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:600)
at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:534)
at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:527)
at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.close(AutorecoveringChannel.java:68)
at com.sam.hello_rabbitmq.Provider.main(Provider.java:60)关键堆栈信息是:inequivalent arg 'durable' for queue 'helloRabbit' in vhost '/': received 'false' but current is 'true',说是helloRabbit这个队列durable(是否需要持久化)
参数已经设定成了true 但是代码中指定的是false,冲突了,纳尼?访问RabbitMQ管理页面:http://localhost:15672/#/queues 发现已经存在一个队列helloRabbit,
点helloRabbit的链接,发现队列的durable属性确实是true。哦,原来我之前在做别的练习的时候,创建过一个叫这个名字的队列了,而且属性值刚好为true.

那么接下来删掉这个既存的队列

再去执行Provider.java,后台打印了内容,并且队列中有了一条ready的消息。


问题解决!
- 执行HelloConsumer.java,预想的结果是在启动后,控制台直接打印出log并且RabbitMQ管理页面没有ready的消息:

结果符合预期。
到此,全部工作完美结束。
RabbitMQ入门:Hello RabbitMQ 代码实例的更多相关文章
- RabbitMQ入门-初识RabbitMQ
初识RabbitMQ 要说RabbitMQ,我们不得不先说下AMQP.AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面 ...
- RabbitMQ入门-从HelloWorld开始
从读者的反馈谈RabbitMQ 昨天发完<RabbitMQ入门-初识RabbitMQ>,我陆陆续续收到一些反馈.鉴于部分读者希望结合实例来讲 期待下篇详细,最好结合案例.谢谢! 哪都好,唯 ...
- [转]RabbitMQ入门教程(概念,应用场景,安装,使用)
原文地址:https://www.jianshu.com/p/dae5bbed39b1 RabbitMQ 简介 RabbitMQ是一个在AMQP(Advanced Message Queuing Pr ...
- RabbitMQ入门-高效的Work模式
扛不住的Hello World模式 上篇<RabbitMQ入门-从HelloWorld开始>介绍了RabbitMQ中最基本的Hello World模型.正如其名,Hello World模型 ...
- RabbitMQ入门-消息订阅模式
消息派发 上篇<RabbitMQ入门-消息派发那些事儿>发布之后,收了不少反馈,其中问的最多的还是有关消息确认以及超时等场景的处理. 楼主,有遇到消费者后台进程不在,但consumer连接 ...
- RabbitMQ入门与使用篇
介绍 RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue)协议的开源实现.用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面都非常的优秀 ...
- RabbitMQ入门:总结
随着上一篇博文的发布,RabbitMQ的基础内容我也学习完了,RabbitMQ入门系列的博客跟着收官了,以后有机会的话再写一些在实战中的应用分享,多谢大家一直以来的支持和认可. RabbitMQ入门系 ...
- RabbitMQ入门:路由(Routing)
在上一篇博客<RabbitMQ入门:发布/订阅(Publish/Subscribe)>中,我们认识了fanout类型的exchange,它是一种通过广播方式发送消息的路由器,所有和exch ...
- RabbitMQ入门:发布/订阅(Publish/Subscribe)
在前面的两篇博客中 RabbitMQ入门:Hello RabbitMQ 代码实例 RabbitMQ入门:工作队列(Work Queue) 遇到的实例都是一个消息只发送给一个消费者(工作者),他们的消息 ...
随机推荐
- MySQL知识总结(四)二进制日志
1 定义 bin-log日志记录了所有的DDL和DML的语句,但不包括查询的语句,语句以事件的方式保存,描述了数据的更改过程,此日志对发生灾难时数据恢复起到了极为重要的作用. 2 开启 mysql默认 ...
- FTP response 421 received. Server closed connection
现象: 在springboot的定时器轮询去下载ftp文件时,报以下错误: org.apache.commons.net.ftp.FTPConnectionClosedException: FTP r ...
- Linux - Confluence搭建
0. 摘要 Confluence自身携带内置数据库,对于生产环境建议搭建外置数据库,Confluence通过相应驱动连接上.并操作数据库.Confluence支持多种数据库,本文采用MySQL. 1. ...
- node-webkit,nwjs 打包启动启动很慢解决办法
要开发一个桌面程序,可选择的有nwjs和electron,但是electron不支持xp,客户还是有一部分系统是用xp的,只能用nwjs. 由于程序需要安装很多npm的模块,node_module文件 ...
- oracle之修改/忘记用户密码
一.修改/忘记用户密码: ## 修改oracle用户名和密码 sqlplus /nolog ## DBA角色进入 conn /as sysdba; ## 查看用户列表 select username ...
- standard cell timing model
standard cell timing model 主要包括两方面的信息: Cell Delay calculation Output Transition calculation 首先,cel ...
- http协议中的keeplive是做什么的?它的适应场景是什么?
1.Http底层也是通过TCP传输的. 2.HTTP keep-alive Http是一个”请求-响应”协议,它的keep-alive主要是为了让多个http请求共享一个Tcp连接,以避免每个Http ...
- Xamarin 编写混合APP趟坑记录(二)
前言 公司要开发一个App,为了便于维护和更新,而不用每次去苹果审核,采用的是混合开发方式:用WebVie+WebApp的方式. 因为本人不会Java和ObjectC,公司又不想花钱招这两个岗位的人, ...
- MySQL学习【第六篇sql语句下】
一.select高级用法 1.传统连接(只能内连接,取交集,效率最慢) 1.根据两张表查询张三成绩 select t1.sname,t2.mark from t1,t2 where t1.sid=t2 ...
- AngularJS中的按需加载ocLazyLoad插件应用;
一.前言 ocLoayLoad是AngularJS的模块按需加载器.一般在小型项目里,首次加载页面就下载好所有的资源没有什么大问题.但是当我们的网站渐渐庞大起来,这样子的加载策略让网速初始化速度变得越 ...