Java与RabbitMQ(三)Rabbirmq JAVA编程之Hello World!

来源:互联网 发布:激光亚克力切割机软件 编辑:程序博客网 时间:2024/06/07 12:12

本系列教程主要针对使用java语言进行Rabbitmq的相关编程。阅读前请确认已经安装过rabbit服务。关于如何安装rabbitmq,请参考如何使用rabbitmq.

介绍

RabbitMQ是一个消息代理中间件。主要概念就是:接收、转发消息。你也可以将它看成是一个邮局:当你把邮寄物品投递到邮箱时,你可以确认这件物品最终会到达你指定的收件人手中。你可以将RabbitMQ比喻成邮箱、邮局、邮差。

RabbitMQ 和邮局最主要区别就是,RabbitMQ不处理纸质信件,它的职责是接收、存储和发送二进制数据-消息。

一般来说,RabbitMQ 和消息机制有一些专业术语需要了解一下:

  • 生产者   生产,意味着只需要发送消息。发送消息的程序就是生产者。我们用统一图样来表示生产者:

    这里写图片描述

  • 队列  类似于我们的邮箱。队列是在RabbitMQ进程中的。在一个队列里可以存储RabbitMQ和你的应用程序之间的消息数据流。队列理论上来说是不受任何限制的,它可以存放你想要存放任意数量的消息数据 —— 你可以认为它是一个无限的缓冲区。许多生产者可以发送消息到队列中,许多消费者也可以从队列中获取消息数据。我们也用统一图样来表示队列:

    这里写图片描述

  • 消费者  消费者好比收件人。等待接收消息的程序即可称之为消费者。我们也用统一图样来表示消费者:

    这里写图片描述

注意:生产者、消费者和消息代理不一定在同一个机器上,实际场景中大都是在分布式集群环境中。

Hello World

使用Java 客户端

这部分教程中我们将会编写两个java程序。一个发送一条简单消息的生产者,和一个消费者接收消息并打印到控制台。我们不谈java API的一些细节,先把注意力集中在这个简单的入门程序中。
在下面的图例中,P 是我们的生产者,C 是我们的消费者。中间的盒子是一个队列 —— RabbitMQ用于为消费者缓存消息。

这里写图片描述

Java client library
RabbitMQ 允许使用多种协议. 本系列教程使用的是 AMQP 0-9-1, 是一个开放的通用的消息传递协议。 针对不同语言,有不同的RabbitMQ连接客户端。 本教程我们使用RabbitMQ提供的java客户端连接工具。
你可以下载java client lib.jar包,并校验一下签名。下载后解压缩jar包到你工作目录中:

$ unzip rabbitmq-java-client-bin-*.zip$ cp rabbitmq-java-client-bin-*/*.jar ./

我们也可以使用如下Maven依赖引入:

<dependency>    <groupId>com.rabbitmq</groupId>    <artifactId>amqp-client</artifactId>    <version>3.6.5</version></dependency>

现在我们已经有了java客户端连接的依赖了,可以开始写一写代码了。

发送消息

这里写图片描述

我们写一个消息发送的类Send、一个接收消息的类Recv.
在Send.java类中,需要引入以下几个类:

import com.rabbitmq.client.ConnectionFactory;import com.rabbitmq.client.Connection;import com.rabbitmq.client.Channel;

设置类并命名队列名称为”hello”:

public class Send {  private final static String QUEUE_NAME = "hello";  public static void main(String[] argv)      throws java.io.IOException {      //do your job...  }}

然后我们继续在main方法中添加连接到RabbitMQ的代码:

//创建连接工厂类ConnectionFactory factory = new ConnectionFactory();//设置需要连接到的RabbitMQ主机地址factory.setHost("localhost");//创建一个连接Connection connection = factory.newConnection();//创建一个信道Channel channel = connection.createChannel();

Connection抽象了socket连接,并负责对我们的协议版本的协商和身份验证等。这里我们连接到了本地机器的一个代理服务器,如果我们要连接到其他机器,则只需调整一下ip地址即可。

然后我们创建了一个channel,它会提供大部分的API帮助我们在RabbitMQ中做想做的事情。

发送消息,我们需要声明一个该消息缓存的队列;声明过后,我们就可以把消息发送到队列中了。

//声明一个队列,队列名称为"hello"channel.queueDeclare(QUEUE_NAME, false, false, false, null);String message = "Hello World!";channel.basicPublish("",QUEUE_NAME,null,message.getBytes());System.out.println(" [x] Sent '" + message + "'");

队列声明是幂等的 —— 只有指定的队列不存在时才会创建。消息内容是byte[]类型,所以你可以指定任意编码。

最后,关闭资源(channel、connection):

channel.close();connection.close();

这里是完整的Send.java类的源码链接。

消息发送不工作了!
如果这是你第一次使用RabbitMQ并且你也看不到发送的消息,可能会很困惑是哪里出了问题。这可能是RabbitMQ启动时赋予的空间不足(默认情况下是1Gb)导致服务器拒绝接受消息。这时你需要检查日志文件,可能的话还需要降低空间大小的限制。配置文件的文档教你如何设置disk_free_limit

接收消息

消费者是从RabbitMQ接收消息,所以跟前面的生产者有点不同只是发送了一条简单的消息,消费者需要保持连接监听消息并输出它们。

这里写图片描述

Recv.java类同样需要导入一些重要的类:

import com.rabbitmq.client.ConnectionFactory;import com.rabbitmq.client.Connection;import com.rabbitmq.client.Channel;import com.rabbitmq.client.Consumer;import com.rabbitmq.client.DefaultConsumer;

DefaultConsumer Consumer 接口的一个实现类,我们用它缓存服务端发送过来的消息。
消费者连接设置和生产者是一样的。打开一个连接、信道,声明一个将去消费的队列。注意:消费者这些设置参数应该和生产者是一样的。

public class Recv {  private final static String QUEUE_NAME = "hello";  public static void main(String[] argv)      throws java.io.IOException,             java.lang.InterruptedException {    ConnectionFactory factory = new ConnectionFactory();    factory.setHost("localhost");    Connection connection = factory.newConnection();    Channel channel = connection.createChannel();    channel.queueDeclare(QUEUE_NAME, false, false, false, null);    System.out.println(" [*] Waiting for messages. To exit press CTRL+C");    //do your job ...    }}

注意:这里我们同样声明了一个名称和生产者一致的队列。因为我们可能在生产者发送消息前启动消费服务,我们需要确保在消费消息数据之前队列是存在的。

我们要告诉生产者通过队列将消息传给消费者。由于生产者发送消息是异步的,消费端提供了一个对象(该对象缓存消费端将要使用的消息)的回调。这就是DefaultConsumer 所做的事情。

Consumer consumer = new DefaultConsumer(channel) {      @Override      public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)          throws IOException {        String message = new String(body, "UTF-8");        System.out.println(" [x] Received '" + message + "'");      }    };    channel.basicConsume(QUEUE_NAME, true, consumer);

这里是完整的Recv.java类的源码链接。

运行程序实例

可以导入maven工程到eclipse(idea),执行Send.java、Recv.java的main方法

step1:运行Recv的main方法,消费者等待队列的消息,在消费者一端的控制台输出如下:

[*] Waiting for messages. To exit press CTRL+C

step2:运行Send的main方法,生产者发送消息,在生产者一端的控制台输出如下消息后,并且关闭了服务连接:

 [x] Sent 'Hello World!'

此时查看消费者一端,可以看到控制台增加了一条输出内容,正是从队列获取的消息:

 [*] Waiting for messages. To exit press CTRL+C [x] Received 'Hello World!'

step3:这时候我再次启动一个服务(运行Send的main方法),又往队列发送一条Hello World!的消息:

 [x] Sent 'Hello World!'

此时继续查看消费者一端,可以看到控制台又增加了一条输出内容,正是第二次从队列获取的消息:

 [*] Waiting for messages. To exit press CTRL+C [x] Received 'Hello World!' [x] Received 'Hello World!'

执行完程序后,你也可以进入web界面查看队列状态。关于更多RabbitMQ的web监控管理界面内容,可以参考启动rabbitmq web管理后台插件

使用javac -cp命令

编译源代码

javac -cp rabbitmq-core.jar Send.java Recv.java

运行前面编译后的字节码文件,命令行操作这里要求classpath添加了rabbitmq-client.jar的依赖

java -cp .:commons-io-1.2.jar:commons-cli-1.1.jar:rabbitmq-client.jar Send
java -cp .:commons-io-1.2.jar:commons-cli-1.1.jar:rabbitmq-client.jar Recv

windows环境下,使用分号符;替代:执行命令。
在终端执行时,消费者一直是运行着的,在等待着接收消息(仅限终端执行Ctrl-C 停止运行),所以你可以使用命令再运行一个生产者去发送一个新的消息。

可以在RabbitMQ的安装目录下sbin目录下使用rabbitmqctl list_queues命令查看队列的一些属性:

C:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.5\sbin>rabbitmqctl list_queuesListing queues ...hello_queue     0

学完这节,是时候学习第二节内容,去创建一个工作队列了。

原文链接:http://www.rabbitmq.com/tutorials/tutorial-one-java.html

1 0