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的消息。
问题解决!
- SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
- 执行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) 遇到的实例都是一个消息只发送给一个消费者(工作者),他们的消息 ...
随机推荐
- Django之模板配置(template)
Django模板系统 官方文档 jinja2模块中文 jinja2模块官方 常用语法 只需要记两种特殊符号: {{ }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 在Djan ...
- Apache服务器下使用 ab 命令进行压力测试
ab是Apache超文本传输协议(HTTP)的性能测试工具. 其设计意图是描绘当前所安装的Apache的执行性能,主要是显示你安装的Apache每秒可以处理多少个请求. #ab -v可以看出其基本信息 ...
- HDU1042 N!(大数问题,万进制)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1042 N! Time Limit: 10000/5000 MS (Java/Others) M ...
- 渲染引擎,HTML解析
这是how browser to work 的翻译 转自:携程设计委员会 渲染引擎 渲染引擎的职责是……渲染,也就是把请求的内容显示到浏览器屏幕上. 默认情况下渲染引擎可以显示HTML,XML文档以及 ...
- Spring Cloud和Dubbo整合开发笔记(1)
一.需求背景: 公司内部老项目微服务技术栈使用Dubbo, 新项目技术栈使用主流的Spring Cloud相关组件开发,新旧项目涉及交互调用,无法直接通信数据传递. 老项目基于Dubbo,重构代码升级 ...
- OpenGL 球体世界
一.类似公自转 二.核心代码 //图形渲染 void RenderScene() { //清楚缓存区:颜色缓存区.深度缓存区.模版缓存区 glClear(GL_COLOR_BUFFER_BIT|GL_ ...
- Delphi泛型动态数组的扩展--转贴
此文章转载于http://www.raysoftware.cn/?p=278&tdsourcetag=s_pcqq_aiomsg的博客 从Delphi支持泛型的第一天起就有了一种新的动态数组类 ...
- 【10.14】Bug Bounty Write-up总结
我很喜欢今天的看到的write-up,因为作者是针对他对一个网站整体进行漏洞挖掘的过程写的,内容包括几个不同的漏洞,从中能够学习到怎样系统性的挖掘漏洞. write-up地址:[Bug bounty ...
- 时间序列分析工具箱——timetk
目录 时间序列分析工具箱--timetk timetk 的主要用途 加载包 数据 timetk 教程: PART 1:时间序列机器学习 PART 2:转换 翻译自<Demo Week: Time ...
- 日志工具——log4j
资料参考自:http://www.codeceo.com/article/log4j-usage.html 关于日志的基本概念以及从入门到实战,请参见:http://www.cnblogs.com/L ...