【RabbitMQ】HelloWorld
初识RabbitMQ
RabbitMQ是一个消息代理人。它的主要目的很简单:接受并推送消息。我们可以将它理解为一个邮局:当你邮寄一封邮件到邮箱里,可以非常确定邮递员会将它送到收件人手中。打这种比方来将RabbitMQ看做一个邮局,邮箱,邮递员。
RabbitMQ和邮局的主要区别在于它不需要纸,它所接收的,存贮的以及推送的是二进制数据----消息。
下面介绍一些术语:
生产(Producing)就是发送数据,一个发送消息的程序被称为生产者(Producer)。
队列(queue)代表着邮箱。它依附在RabbitMQ内部。尽管消息在RabbitMQ和你的应用程序之间传输,它们也只能被保存在队列中。一个队列没有被绑定任何限制,它可以存放任意多的消息----它本质上就是一个无限大小的缓冲区。多个生产者可以发送消息到同一个队列中,多个消费者也可以从同一个队列中消费消息。
消费(Consuming)即接收。一个等待接收消息的程序被称为消费者(Consumer)。
注意:生产者,消费者,代理人不需要在同一台机器上。
"HelloWorld"
这部分我们将使用Java写两个小程序:一个生产者发送一条消息,一个消费者接收并打印该条消息(先决条件:要在本地启动RabbitMQ服务器http://www.rabbitmq.com/install-debian.html)。流程如下图所示:
导入maven依赖:
<dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>4.0.1</version> </dependency>
Sending
我们将会调用Send和接收端Recv。发送端将会连接到RabbitMQ服务,发送一条消息后退出。
在Send.java,导入下列包:
import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Channel;
初始化类和队列名:
public class Send { private final static String QUEUE_NAME = "hello"; public static void main(String[] argv) throws java.io.IOException { ... } }
然后创建到RabbitMQ服务的连接:
ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel();
这个connection抽象了socket连接,并且为我们管理好了协议版本和安全认证等。这里我们连接的是在本机的代理人----因为127.0.0.1.如果你想连接到其它的机器上,只需要更改IP地址就可以。
下面创建一个channel,大多数API在它里面驻留来获取数据。
我们必须声明一个队列来向其中发送消息:
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 + "'");
声明一个队列是幂等的----它仅仅会在不存在的时候创建。消息内容是字节数组,所以你可以任意编码。
最后,关闭channel和connection:
channel.close();
connection.close();
Receiving
接收方负责推送从RabbitMQ得到的消息,不像发送方只发送单条消息,我们需要让接收方保持运行状态,不断监听消息并打印。
导入的包与发送时基本相同:
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接口的实现类,我们将用它来缓冲服务器推送给我们的消息。
初始化和sender一样,打开一个connection和一个channel,声明我们要消费消息的队列。注意它需要与发送消息的队列相匹配。
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"); ... } }
注意我们在这里也声明了队列,这是因为可能receiever运行在sender之前,我们要确保在监听消息时这个队列是存在的。
现在我们要告诉服务器准备从队列中发送消息。由于服务器是异步的推送给我们消息,我们以对象的形式提供一个回调,它将缓冲消息,直到我们准备好使用它。这就是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,他会开始监听消息,此时我们运行一次Send.java,就会发送一条消息,同时Recv会接收一条消息。