在之前的一篇博客RabbitMQ入门:认识并安装RabbitMQ(以Windows系统为例)中,我们安装了RabbitMQ并且对其也有的初步的认识,今天就来写个入门小例子来加深概念理解并了解代码怎么实现。

本篇博客围绕下面几个方面展开:

  1. 代码前的理论热身
  2. 代码实例:Hello RabbitMQ
  3. 运行代码并调试问题

Now, Let's begin !

一、代码前的理论热身

我们来看张图:

Publisher(生产者)生成消息,然后publish(发布)消息到exchange(路由器,也有资料翻译成交换机),然后根据路由规则将消息传递到Queue(队列),最终交由Consumer(消费者)进行消费处理。

这里的生产者和消费者都是我们的应用,因此我们的代码中要实现这两个部分。

中间的节点就是RabbitMQ 提供的内容,需要再生产者和消费者里面调用其接口来定义和使用这些节点。

二、代码实例:Hello RabbitMQ

  1. 首先来实现生产者,这里我没有用Publisher做类名,而是用的Provider,没有特别的用意,就是在起名字的时候不小心写成了这样,不需要在意这个细节,O(∩_∩)O。

    1. package com.sam.hello_rabbitmq;
    2.  
    3. import java.io.IOException;
    4. import java.util.concurrent.TimeoutException;
    5.  
    6. import com.rabbitmq.client.Channel;
    7. import com.rabbitmq.client.Connection;
    8. import com.rabbitmq.client.ConnectionFactory;
    9.  
    10. public class Provider {
    11.  
    12. //定义队列名
    13. static String QUEUE_NAME = "helloRabbit";
    14.  
    15. public static void main(String[] args) {
    16. ConnectionFactory factory = new ConnectionFactory();
    17. factory.setHost("localhost");
    18. Connection connection = null;
    19. Channel channel = null;
    20. try {
    21. //1.创建连接和通道
    22. connection = factory.newConnection();
    23. channel = connection.createChannel();
    24.  
    25. //2.为通道声明队列
    26. channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    27.  
    28. //3.发布消息
    29. String msg = " hello rabbitmq, welcome to sam's blog.";
    30. channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
    31. System.out.println("provider send a msg: " + msg);
    32. } catch (IOException e) {
    33. e.printStackTrace();
    34. } catch (TimeoutException e) {
    35. e.printStackTrace();
    36. } finally {
    37. //4.关闭连接
    38. if (channel != null) {
    39. try {
    40. channel.close();
    41. } catch (IOException e) {
    42. e.printStackTrace();
    43. } catch (TimeoutException e) {
    44. e.printStackTrace();
    45. }
    46. }
    47.  
    48. if (connection != null) {
    49. try {
    50. connection.close();
    51. } catch (IOException e) {
    52. e.printStackTrace();
    53. }
    54. }
    55. }
    56.  
    57. }
    58.  
    59. }

    在第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呢?因为如果声明了队列,可以不声明路由器。

  2. 接着来实现消费者,消费者实现和生产者过程差不多,但是在这里并没有关闭连接和通道,是因为要消费者一直等待随时可能发来的消息。代码如下:
    1. package com.sam.hello_rabbitmq;
    2.  
    3. import java.io.IOException;
    4. import java.util.concurrent.TimeoutException;
    5. import com.rabbitmq.client.Channel;
    6. import com.rabbitmq.client.Connection;
    7. import com.rabbitmq.client.ConnectionFactory;
    8. import com.rabbitmq.client.Consumer;
    9. import com.rabbitmq.client.DefaultConsumer;
    10. import com.rabbitmq.client.Envelope;
    11.  
    12. public class HelloConsumer {
    13.  
    14. public static void main(String[] args) {
    15. ConnectionFactory factory = new ConnectionFactory();
    16. factory.setHost("localhost");
    17. Connection connection = null;
    18. Channel channel = null;
    19. try {
    20. // 1.创建连接和通道
    21. connection = factory.newConnection();
    22. channel = connection.createChannel();
    23.  
    24. // 2.为通道声明队列
    25. channel.queueDeclare(Provider.QUEUE_NAME, false, false, false, null);
    26. System.out.println(" **** keep alive ,waiting for messages, and then deal them");
    27. // 3.通过回调生成消费者
    28. Consumer consumer = new DefaultConsumer(channel) {
    29. @Override
    30. public void handleDelivery(String consumerTag, Envelope envelope,
    31. com.rabbitmq.client.AMQP.BasicProperties properties, byte[] body) throws IOException {
    32.  
    33. //获取消息内容然后处理
    34. String msg = new String(body, "UTF-8");
    35. System.out.println("*********** HelloConsumer" + " get message :[" + msg +"]");
    36. }
    37. };
    38.  
    39. //4.消费消息
    40. channel.basicConsume(Provider.QUEUE_NAME, true, consumer);
    41.  
    42. } catch (IOException e) {
    43. e.printStackTrace();
    44. } catch (TimeoutException e) {
    45. e.printStackTrace();
    46. }
    47. }
    48. }

    在第4步中,channel.basicConsume 用来接收消息,用在消费者,有3个参数:String queue, 队列名字,即要从哪个队列中接收消息; boolean autoAck, 是否自动确认,默认true; Consumer callback 消费者,即谁接收消息。

三、运行代码并调试问题

代码写好了,接下来进行测试,

  1. 先来执行下Provider.java,发现报错了:

    1. SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    2. SLF4J: Defaulting to no-operation (NOP) logger implementation
    3. SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
    4. java.io.IOException
    5. at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:124)
    6. at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:120)
    7. at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:142)
    8. at com.rabbitmq.client.impl.ChannelN.queueDeclare(ChannelN.java:952)
    9. at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.queueDeclare(AutorecoveringChannel.java:333)
    10. at com.sam.hello_rabbitmq.Provider.main(Provider.java:36)
    11. 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)
    12. at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66)
    13. at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36)
    14. at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:443)
    15. at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:263)
    16. at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:136)
    17. ... 3 more
    18. 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)
    19. at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:509)
    20. at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:340)
    21. at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:162)
    22. at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:109)
    23. at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:643)
    24. at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47)
    25. at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:581)
    26. at java.lang.Thread.run(Thread.java:745)
    27. 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)
    28. at com.rabbitmq.client.impl.AMQChannel.processShutdownSignal(AMQChannel.java:345)
    29. at com.rabbitmq.client.impl.ChannelN.startProcessShutdownSignal(ChannelN.java:286)
    30. at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:600)
    31. at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:534)
    32. at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:527)
    33. at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.close(AutorecoveringChannel.java:68)
    34. at com.sam.hello_rabbitmq.Provider.main(Provider.java:60)
    1. 关键堆栈信息是: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的消息。

    问题解决!

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

    结果符合预期。

到此,全部工作完美结束。

RabbitMQ入门:Hello RabbitMQ 代码实例的更多相关文章

  1. RabbitMQ入门-初识RabbitMQ

    初识RabbitMQ 要说RabbitMQ,我们不得不先说下AMQP.AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面 ...

  2. RabbitMQ入门-从HelloWorld开始

    从读者的反馈谈RabbitMQ 昨天发完<RabbitMQ入门-初识RabbitMQ>,我陆陆续续收到一些反馈.鉴于部分读者希望结合实例来讲 期待下篇详细,最好结合案例.谢谢! 哪都好,唯 ...

  3. [转]RabbitMQ入门教程(概念,应用场景,安装,使用)

    原文地址:https://www.jianshu.com/p/dae5bbed39b1 RabbitMQ 简介 RabbitMQ是一个在AMQP(Advanced Message Queuing Pr ...

  4. RabbitMQ入门-高效的Work模式

    扛不住的Hello World模式 上篇<RabbitMQ入门-从HelloWorld开始>介绍了RabbitMQ中最基本的Hello World模型.正如其名,Hello World模型 ...

  5. RabbitMQ入门-消息订阅模式

    消息派发 上篇<RabbitMQ入门-消息派发那些事儿>发布之后,收了不少反馈,其中问的最多的还是有关消息确认以及超时等场景的处理. 楼主,有遇到消费者后台进程不在,但consumer连接 ...

  6. RabbitMQ入门与使用篇

    介绍 RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue)协议的开源实现.用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面都非常的优秀 ...

  7. RabbitMQ入门:总结

    随着上一篇博文的发布,RabbitMQ的基础内容我也学习完了,RabbitMQ入门系列的博客跟着收官了,以后有机会的话再写一些在实战中的应用分享,多谢大家一直以来的支持和认可. RabbitMQ入门系 ...

  8. RabbitMQ入门:路由(Routing)

    在上一篇博客<RabbitMQ入门:发布/订阅(Publish/Subscribe)>中,我们认识了fanout类型的exchange,它是一种通过广播方式发送消息的路由器,所有和exch ...

  9. RabbitMQ入门:发布/订阅(Publish/Subscribe)

    在前面的两篇博客中 RabbitMQ入门:Hello RabbitMQ 代码实例 RabbitMQ入门:工作队列(Work Queue) 遇到的实例都是一个消息只发送给一个消费者(工作者),他们的消息 ...

随机推荐

  1. Django之模板配置(template)

    Django模板系统 官方文档 jinja2模块中文 jinja2模块官方 常用语法 只需要记两种特殊符号: {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 在Djan ...

  2. Apache服务器下使用 ab 命令进行压力测试

    ab是Apache超文本传输协议(HTTP)的性能测试工具. 其设计意图是描绘当前所安装的Apache的执行性能,主要是显示你安装的Apache每秒可以处理多少个请求. #ab -v可以看出其基本信息 ...

  3. HDU1042 N!(大数问题,万进制)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1042 N! Time Limit: 10000/5000 MS (Java/Others)    M ...

  4. 渲染引擎,HTML解析

    这是how browser to work 的翻译 转自:携程设计委员会 渲染引擎 渲染引擎的职责是……渲染,也就是把请求的内容显示到浏览器屏幕上. 默认情况下渲染引擎可以显示HTML,XML文档以及 ...

  5. Spring Cloud和Dubbo整合开发笔记(1)

    一.需求背景: 公司内部老项目微服务技术栈使用Dubbo, 新项目技术栈使用主流的Spring Cloud相关组件开发,新旧项目涉及交互调用,无法直接通信数据传递. 老项目基于Dubbo,重构代码升级 ...

  6. OpenGL 球体世界

    一.类似公自转 二.核心代码 //图形渲染 void RenderScene() { //清楚缓存区:颜色缓存区.深度缓存区.模版缓存区 glClear(GL_COLOR_BUFFER_BIT|GL_ ...

  7. Delphi泛型动态数组的扩展--转贴

    此文章转载于http://www.raysoftware.cn/?p=278&tdsourcetag=s_pcqq_aiomsg的博客 从Delphi支持泛型的第一天起就有了一种新的动态数组类 ...

  8. 【10.14】Bug Bounty Write-up总结

    我很喜欢今天的看到的write-up,因为作者是针对他对一个网站整体进行漏洞挖掘的过程写的,内容包括几个不同的漏洞,从中能够学习到怎样系统性的挖掘漏洞. write-up地址:[Bug bounty ...

  9. 时间序列分析工具箱——timetk

    目录 时间序列分析工具箱--timetk timetk 的主要用途 加载包 数据 timetk 教程: PART 1:时间序列机器学习 PART 2:转换 翻译自<Demo Week: Time ...

  10. 日志工具——log4j

    资料参考自:http://www.codeceo.com/article/log4j-usage.html 关于日志的基本概念以及从入门到实战,请参见:http://www.cnblogs.com/L ...