Rabbit MQ Java Api

Overview

RabbitMQ Java client使用com.rabbitmq.clients作为顶层的包,关键的类和接口是:

  • Channel
  • Connection
  • ConnectionFactory
  • Consumer

rabbitmq是通过Channel接口进行协议操作的。Connection用于打开Channel,注册连接的生命周期时间的处理程序和关闭不再需要的连接。Connection是通过ConnectionFactory进行实例化的,该接口可以配置各种连接的设置,如vhost或者username。

rabbitmq的jar包的下载地址为:
http://repo1.maven.org/maven2/com/rabbitmq/amqp-client/5.0.0/amqp-client-5.0.0.jar

Maven:

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

Gradle:

dependencies {
  compile 'com.rabbitmq:amqp-client:5.0.0'
}

Connections和Channels

ConnectionChannel类是整个API的核心,代表AMQP中的connectionchannel,在使用前必须import,如下:

import com.rabbit.clients.Connection;
import com.rabbit.clients.Channel;

Connecting to a broker(连接代理)

下面的代码是用来连接broker的:

ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(hostName);
factory.setPort(portNumber);
Connection conn = factory.newConnection();

当rabbitmq服务器是在本地运行时,上面的那些参数是默认的。


另外,URls可以这样使用:

ConnectionFactory factory = new ConnectionFactory();
factory.setUri("amqp://userName:password@hostName:portNumber/virtualHost");
Connection conn = factory.newConnection();

同样,如果rabbitmq服务在本地运行,那么这些参数是默认的。


Connection可以用来打开一个channel,channel可以用来发布可接收message

Channel channel = conn.creatChannel();

关闭channelconnection如下,关闭channel是一个很好的行为,但是不是必须的,当connection关闭时,channel会自动关闭。

channel.close();
conn.close();

使用Exchanges和Queues

客户端应用工作时是与exchange和queue相关联的。在使用它们之前必须声明,继续上面的例子,下面的代码声明一个exchange和queue,然后将它们绑定在一起:

channel.exchangeDeclare(exchangeName,"direct",true);//声明一个exchange
String queueName = channel.queueDeclare().getQueue();//获取声明queue的名字
channel.queueBind(queueName,exchangeName,routingKey);//将exchange和queue绑定

上面的代码声明了exchange和queue,其中exchange是持久的,非自动删除的,type为“direct”,queue是非持久的,独有的,自动删除的,其名称是自动生成的(也可以自己指定)。queue会和具有相同routing key 的exchange绑定。


channel.exchangeDeclare(exchangeName, "direct", true);
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, exchangeName, routingKey);

上面这段代码与之前的不同之处在于queue的声明,这段代码是根据客户端设置的queue声明的queue。其他的则相同。


exchangeDeclare和queueDeclare是重载的方法,具有不同形式的参数,你也可以重写这些方法以便你自己使用。

Publishing message(发布消息)

使用channel.basicPublish发布消息:

bytes[]  messageBodyBytes="Hello World!".getBytes();
channel.basicPublish(exchangeName,routingkey,null,messageBodyBytes);

为了更好的控制消息的发布,也可以使用更复杂的重载的方法,mandatory和消息属性MessageProperties.PERSISTENT_TEXT_PLAIN

channel.basicPublish(exchangeName, routingKey, mandatory,
                     MessageProperties.PERSISTENT_TEXT_PLAIN,
                     messageBodyBytes);

你也可以使用Builder自定义一些属性:如delivery mode 2,priority 1,content-type "text.plain":

channel.basicPublish(exchangeName, routingKey,
             new AMQP.BasicProperties.Builder()
               .contentType("text/plain")
               .deliveryMode(2)
               .priority(1)
               .userId("bob")
               .build()),
               messageBodyBytes);

下面的例子说明了如何发布自定义headers的消息:

Map<String, Object> headers = new HashMap<String, Object>();
headers.put("latitude",  51.5252949);
headers.put("longitude", -0.0905493);

channel.basicPublish(exchangeName, routingKey,
             new AMQP.BasicProperties.Builder()
               .headers(headers)
               .build()),
               messageBodyBytes);

发布一个带期限(expiration)的message:

channel.basicPublish(exchangeName, routingKey,
             new AMQP.BasicProperties.Builder()
               .expiration("60000")
               .build()),
               messageBodyBytes);

BasicProperties是AMQP(自动生成的容器类)的内部类。

Channels 和 并发注意事项(线程安全)

一般来说,不能在线程之间共享Channel实例,应用应该一个线程声明一个Channel实例而不是在多个线程之间共享一个Channe实例,否则会出现错误。

在一个consume和一个publish的两个线程之间共享channel是安全的。

服务器推送的交付是同时进行的,同时也保证了每一个channel的订阅都被保留。调度机制使用了java.util.concurrent.ExecutorService(一个连接一个服务)。由一个ConnectionFactory创建的Connection由一个处理程序处理是可以的。

当使用手动确认机制时,就必须要考虑确认消息是属于哪个线程的。这与接收处理分发的消息的线程(如:Consumer#handleDelivery下发消息到不同的线程)是不同的。将多个确认消息参数都设置为true是不安全的行为,这会导致双重确认,channel级的协议异常和channel关闭。一次确认一个消息是安全的!

接收订阅的消息

import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;

最有效的接收消息的方式是订阅(subscription),然后订阅的消息就自动的被分发,而不是去请求消息。

在调用与Consumer相关的方法时,个人订阅总是与consumer tag相关。consumer tag可以是由客户端或者服务器端生成的一个标识符。consumer tag与取消消费者有关。不同的Consumer实例必须有不同的consumer tag,不要在连接上重复使用consumer tag。

实现consumer的最简单的方法是将类DefaultConsumer子类化。一个子类的对象可以在basicConsume调用中传递,用于建立订阅。

boolean autoAck = false;
channel.basicConsume(queueName, autoAck, "myConsumerTag",
     new DefaultConsumer(channel) {
         @Override
         public void handleDelivery(String consumerTag,
                                    Envelope envelope,
                                    AMQP.BasicProperties properties,
                                    byte[] body)
             throws IOException
         {
             String routingKey = envelope.getRoutingKey();
             String contentType = properties.getContentType();
             long deliveryTag = envelope.getDeliveryTag();
             // (process the message components here ...)
             channel.basicAck(deliveryTag, false);
         }
     });

Consumers可以使用handleCancelOk和handleCancel方法分别表示明确和不明确的取消操作。

可以通过channel.basicCancel取消一个Consumer:

channel.basicCancel(consumerTag);

最好一个consumer一个channel!

取消息(”Pull API”)

可以使用channel.basicGet方法取message,返回的是一个GetResponse对象,从该对象中可以提取header信息(properties)和消息体。

boolean autoAck = false;
GetResponse response = channel.basicGet(queueName, autoAck);
if (response == null) {
    // No message retrieved.
} else {
    AMQP.BasicProperties props = response.getProps();
    byte[] body = response.getBody();
    long deliveryTag = response.getEnvelope().getDeliveryTag();
    ...

猜你喜欢

转载自blog.csdn.net/gaoyang8320/article/details/78799920