连接RabbitMQ
ConnectionFactory factory=new ConnectionFactory();
factory.setHost(IP_ADDRESS);
factory.setPort(PORT);
factory.setUsername("root");
factory.setPassword("root");
Connection connection=factory.newConnection();//创建连接
ConnectionFactory factory=new ConnectionFactory();//uri方式
factory.setUri("amqp://userName:password@ipAddress:portNumber/virtualHost");
Connection conn=factory.newConnection();//创建连接
Channel channel = conn.createChannel();
Connection可以用来创建多个Channel实例,但是Channel实例不能在线程间共享,应用程序应该为每一个线程开辟一个Channel。多线程间共享Channel实例是非线程安全的。可能会导致在网络上出现错误的通信帧交错。
Channel或Connection中有个isOpen方法可以用来检测其是否已处于开启状态,但是不推荐在生产环境使用,有可能会产生竞争。
Channel的API方法都是可以重载的,比如exchangeDeclare、queueDeclare。
声明交换器
Exchange.DeclareOk exchangeDeclare(String exchange
,String type
,boolean durable
,boolean autoDelete
,boolean internal
,Map arguments
) throws IOException;
删除交换器
Exchange.DeleteOk exchangeDelete(String exchange, boolean ifUnused) throws IOException;
void exchangeDeleteNoWait(String exchange, boolean ifUnused) throws IOException;
Exchange.DeleteOk exchangeDelete(String exchange) throws IOException;
ifUnused用来设置是否在交换器没有被使用的情况下删除。true表示只有在此交换器没有被使用的情况下才会被删除,false表示无论如何这个交换器都要被删除。
声明队列
Queue.DeclareOk queueDeclare() throws IOException
不带任何参数的queueDeclare方法默认创建一个由RabbitMQ命名的、排他的、自动删除的、非持久化的队列(匿名队列)。
Queue.DeclareOk queueDeclare(String queue
,boolean durable
,boolean exclusive
,boolean autoDelete
,Map arguments
) throws IOException;
生产者和消费者都能够使用queueDeclare来声明一个队列,但是如果消费者在同一个信道上订阅了另一个队列,就无法再声明队列了。必须先取消订阅,然后将信道置为“传输”模式,之后才能声明队列。
删除队列
Queue.DeleteOk queueDelete(String queue) throws IOException;
Queue.DeleteOk queueDelete(String queue, boolean ifUnused, boolean ifEmpty) throws IOException;
void queueDeleteNoWait(String queue, boolean ifUnused, boolean ifEmpty) throws IOException;
//queue表示队列名,ifUnused表示该队列是否处于使用中才能删除,ifEmpty表示该队列是否要为空(没有消息堆积)才能删除
清空队列
Queue.PurgeOk queuePurge(String queue) throws IOException;
//该方法用于清空队列中的消息,但不删除队列
队列和交换机绑定
Queue.BindOk queueBind(String queue
, String exchange
, String routingKey
) throws IOException;
Queue.BindOk queueBind(String queue
, String exchange
, String routingKey
, Map arguments
) throws IOException;
void queueBindNoWait(String queue
, String exchange
, String routingKey
, Map arguments
) throws IOException;
//queue表示队列名,exchange表示交换器名,routingKey表示路由键,arguments表示关于绑定的一些参数
队列和交换机解绑
Queue.UnbindOk queueUnbind(String queue, String exchange, String routingKey) throws IOException;
Queue.UnbindOk queueUnbind(String queue, String exchange, String routingKey
, Map arguments) throws IOException;
交换器和交换器绑定(调用该方法进行绑定后,消息会从source转发器发送到destination转发器)
Exchange.BindOk exchangeBind(String destination, String source, String routingKey) throws IOException;
Exchange.BindOk exchangeBind(String destination, String source, String routingKey
, Map arguments) throws IOException;
void exchangeBindNoWait(String destination, String source, String routingKey
, Map arguments) throws IOException;
//destination表示目标转发器,source表示原转发器,routingKey表示路由键,arguments表示绑定的一些参数
交换器的使用并不真正耗费服务器的性能,而队列会。如果要衡量RabbitMQ的QPS(每秒查询率)只需要看队列的即可。
发送消息
void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
throws IOException;
void basicPublish(String exchange, String routingKey, boolean mandatory, BasicProperties props
, byte[] body) throws IOException;
void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate
, BasicProperties props, byte[] body) throws IOException;
消费消息
RabbitMQ的消费模式分为两种:推模式和拉模式。推模式采用Basic.Consume进行消费,而拉模式则是调用Basic.Get进行消费。
在推模式中,可以通过持续订阅的方式来消费消息,接收消息一般通过实现Consumer接口或者继承DefaultConsumer类来实现,当调用与Consumer相关的API方法时,不同的订阅采用不同的消费者标签consumerTag来区分彼此,在同一个Channel中的消费者也需要通过唯一的消费者标签以作区分。
String basicConsume(String queue, Consumer callback) throws IOException;
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal
, boolean exclusive, Map arguments, Consumer callback) throws IOException;
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal
, boolean exclusive, Map arguments, DeliverCallback deliverCallback,
CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException;
queue:队列的名称。
autoAck:设置是否自动确认,建议设为false。
consumerTag:消费者标签,用来区分多个消费者。
noLocal:设置为true则表示不能将同一个Connection中生产者发送的消息传送给这个Connection中的消费者。
exclusive:是否排他。
arguments:设置消费者的其他参数。
callback:设置消费者的回调函数。用来处理RabbitMQ推送过来的消息,比如重写DefaultConsumer的handleDelivery方法。
还可以重写更多的方法,如:handleConsumeOk(会在其他方法之前调用,返回消费者标签)、handleCancelOk、handleCancel、handleShutdownSignal(当Channel或者Connection关闭的时候会调用)、handleRecoverOk。
拉模式
通过channel.basicGet方法可以单条地获取消息,其返回值是GetRespone。Channel类的basicGet方法没有重载。
GetResponse basicGet(String queue, boolean autoAck) throws IOException;
Basic.Consume将信道置为投递模式,直到取消队列的订阅为止,在投递模式期间,RabbitMQ会不断的推送消息给消费者,当然推送消息的个数还是会受到Basic.Qos的限制。如果只是想要获取单条消息而不是持续订阅,建议还是使用Basic.Get进行消费,但是不能通过在循环里调用basicGet来代替basicConsume,这会严重影响RabbitMQ的性能,一般还是使用Basic.Consume,具有较高的吞吐量。
消费端的确认与拒绝
消费者在订阅队列时,可以指定autoAck参数,当autoAck等于false时,RabbitMQ会等待消费者显式地回复确认信号后才从内存(或者磁盘)中移去消息(实质上是先打上删除标记,之后再删除)。当autoAck等于true时,RabbitMQ会自动把发送出去的消息置为确认,然后从内存(或磁盘)中删除,而不管消费者是否真正地消费到了这些消息。
当autoAck=false时,对于RabbitMQ服务器端而言,队列中的消息分成了两部分:一部分是等待投递给消费者的消息;一部分是已经投递给消费者,但是还没有收到消费者ack信号的消息。如果服务器端一直没有收到消费者的ack信号,并且消费此消息的消费者已经断开连接,则服务器端会安排该消息重新进入队列,等待投递给下一个消费者(也可能还是原来的那个消费者)。
RabbitMQ不会为未确认的消息设置超时时间,它判断此消息是否需要重新投递给消费者的唯一依据是消费该消息的消费者连接是否已经断开,这么设计的原因是RabbitMQ允许消费者消费一条消息的时间可以很久很久。
在消费者接受到消息后,如果想明确拒绝当前的消息而不是确认,可以调用channel.basicReject方法(Basic.Reject)来告诉RabbitMQ拒绝这个消息。
void basicReject(long deliveryTag, boolean requeue) throws IOException;
//deliveryTag可以看做消息的编号 如果requeue参数为true,则RabbitMQ会将这条消息存入队列,以便可以发送给下一个订阅的消费者
//如果requeue参数为false,则RabbitMQ立即会把消息从队列中溢出,而不会把它发送给新的消费者。
Basic.Reject命令一次只能拒绝一条消息,如果想要批量拒绝消息,则可以使用Basic.Nack这个命令,对应的方法是channel.basicNack。
void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException;
//multiple为false则表示拒绝编号为deliveryTag的这一条消息
//multiple为true则表示拒绝编号deliveryTag之前所有未被当前消费者确认的消息
将channel.basicReject或者channel.basicNack中的requeue设置为false,可以启用死信队列的功能。死信队列可以通过检测被拒绝或者为送达的消息来追踪问题。
AMQP中还有一个命令Basic.Recover具备可重入队列的特性。
Basic.RecoverOk basicRecover(boolean requeue) throws IOException;
//该方法用于请求RabbitMQ重新发送还未被确认的消息。
//如果为true,则未被确认的消息会被重新加入到队列中,对于同一条消息,可能会被分配给与之前不同的消费者。
//如果为false,则同一条消息会被分配给与之前相同的消费者。
关闭连接
Connection和Channel所具备的生命周期如下:
Connection和Channel最终都会称为Closed的状态,无论是程序正常调用的关闭方法,或者是客户端的异常,再或者是发生了网络异常。
getCloseReason方法可以让你知道对象关闭的原因。