Java环境下使用RabbitMQ客户端需要导入ampq-client库(RabbitMQ的Java Client库,这里我们使用3.6.5版本) ,RabbitMQ服务器使用的是本地RabbitMQ 3.6.6版本。
Maven环境配置
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.6.5</version>
</dependency>
Gradle环境
compile group: 'com.rabbitmq', name: 'amqp-client', version: '3.6.5'
RabbitMQ使用的结构示意图如下:
从示意图可以看出消息生产者并没有直接将消息发送给消息队列,而是通过建立与Exchange的Channel,将消息发送给Exchange,Exchange根据规则,将消息转发给指定的消息队列。消费者通过建立与消息队列相连的Channel,从消息队列中获取消息。
这里谈到的Channel可以理解为建立在生产者/消费者和RabbitMQ服务器之间的TCP连接上的虚拟连接,一个TCP连接上可以建立多个Channel。 RabbitMQ服务器的Exchange对象可以理解为生产者发送消息的邮局,消息队列可以理解为消费者的邮箱。Exchange对象根据它定义的规则和消息包含的routing key以及header信息将消息转发到消息队列。
根据转发消息的规则不同,RabbitMQ服务器中使用的Exchange对象有四种,Direct Exchange, Fanout Exchange, Topic Exchange, Header Exchange,如果定义Exchange时没有指定类型和名称, RabbitMQ将会为每个消息队列设定一个Default Exchange,它的Routing Key是消息队列名称。
RabbitMQ Java Client的官网示例有6个,本篇只使用三个例程,分别是使用默认Default Exchange的消息生产/消费,使用Direct Exchange的消息生产/消费,以及RPC方式的消息生产/消费。
为了测试方便,我们新定义了一个virutal host,名字是test_vhosts,定义了两个用户rabbitmq_producer和rabbitmq_consumer, 设置其user_tag为administrator(可以进行远程连接), 为它们设置了访问test_vhosts下所有资源的权限。
使用默认Default Exchange的消息生产/消费
我们定义一个生产者程序,一个消费者程序。
生产者程序代码如下:
public class ProducerApp
{
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = null;
Channel channel = null;
try
{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setPort(5672);
factory.setUsername("rabbitmq_producer");
factory.setPassword("123456");
factory.setVirtualHost("test_vhosts");
//创建与RabbitMQ服务器的TCP连接
connection = factory.newConnection();
channel = connection.createChannel();
channel.queueDeclare("firstQueue", true, false, false, null);
String message = "First Message";
channel.basicPublish("", "firstQueue", null, message.getBytes());
System.out.println("Send Message is:'" + message + "'");
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
if(channel != null)
{
channel.close();
}
if(connection != null)
{
connection.close();
}
}
}
关于生产者的代码有几点说明:
1) RabbitMQ Java Client示例提供的ConnectionFactory属性设置的代码只有一句:
factory.setHost("localhost");
这句代码表示使用rabbitmq服务器默认的virutal host(“/”),默认的用户guest/guest进行连接,但是如果这段代码运行在远程机器上时, 将因为guest用户不能用于远程连接RabbitMQ服务器而运行失败,上面提供的代码是可以进行建立远程连接的代码。
2)Channel建立后,调用Channel.queueDeclare方法创建消息队列firstQueue。
Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map<String, Object> arguments) throws IOException;
这个方法的第二个参数durable表示建立的消息队列是否是持久化(RabbitMQ重启后仍然存在,并不是指消息的持久化),第三个参数exclusive 表示建立的消息队列是否只适用于当前TCP连接,第四个参数autoDelete表示当队列不再被使用时,RabbitMQ是否可以自动删除这个队列。 第五个参数arguments定义了队列的一些参数信息,主要用于Headers Exchange进行消息匹配时。
3)生产者发送消息使用Channel.basicPublish方法。
void basicPublish(String exchange, String routingKey,
BasicProperties props, byte[] body) throws IOException;
第一个参数exchange是消息发送的Exchange名称,如果没有指定,则使用Default Exchange。 第二个参数routingKey是消息的路由Key,是用于Exchange将消息路由到指定的消息队列时使用(如果Exchange是Fanout Exchange,这个参数会被忽略), 第三个参数props是消息包含的属性信息。RabbitMQ的消息属性和消息体是分开的,不像JMS消息那样同时包含在javax.jms.Message对象中,这一点需要特别注意。 第四个参数body是RabbitMQ消息体。 我们这里调用basicPublish方法发送消息时,props参数为null,因而我们发送的消息是非持久化消息,如果要发送持久化消息,我们需要进行如下设置:
AMQP.BasicProperties props =
new AMQP.BasicProperties("text/plain",
"UTF-8",
null,
2,
0, null, null, null,
null, null, null, null,