rabbitMq在实际发消息的时候会把 nextPublishSeqNo 存入到 unconfirmedSet 中
// com.rabbitmq.client.impl.ChannelN#basicPublish()
public void basicPublish(String exchange, String routingKey,
boolean mandatory, boolean immediate,
BasicProperties props, byte[] body)
throws IOException
{
// 只有当开启消息确认和事务消息时,才会在初始时设置 nextPublishSeqNo=1
if (nextPublishSeqNo > 0) {
unconfirmedSet.add(getNextPublishSeqNo());
nextPublishSeqNo++;
}
if (props == null) {
props = MessageProperties.MINIMAL_BASIC;
}
AMQCommand command = new AMQCommand(
new Basic.Publish.Builder()
.exchange(exchange)
.routingKey(routingKey)
.mandatory(mandatory)
.immediate(immediate)
.build(), props, body);
try {
transmit(command);
} catch (IOException e) {
metricsCollector.basicPublishFailure(this, e);
throw e;
}
metricsCollector.basicPublish(this);
}
在消息回调时处理seqNo
// com.rabbitmq.client.impl.ChannelN#handleAckNack()
private void handleAckNack(long seqNo, boolean multiple, boolean nack) {
if (multiple) {
// 如果是批量的,则把当前seqNo以及之前的全部清除
unconfirmedSet.headSet(seqNo + 1).clear();
} else {
unconfirmedSet.remove(seqNo);
}
synchronized (unconfirmedSet) {
onlyAcksReceived = onlyAcksReceived && !nack;
if (unconfirmedSet.isEmpty())
unconfirmedSet.notifyAll();
}
}
nextPublishSeqNo 不会被发送到 rabbitMq 。如何保证与 deliveryTag 对应?在一个连接存续期间,服务器返回的 deliveryTag 会自增,需要应用程序自己保证每发一条信息自增1,与服务器保持一致。
非确认消息,不会使用到 nextPublishSeqNo 。
为了保证能及时的响应异步回调,驱动程序会启动一个线程专门监听rabbitMq服务消息。
// com.rabbitmq.client.impl.AMQConnection.MainLoop
private class MainLoop implements Runnable {
/**
* Channel reader thread main loop. Reads a frame, and if it is
* not a heartbeat frame, dispatches it to the channel it refers to.
* Continues running until the "running" flag is set false by
* shutdown().
*/
@Override
public void run() {
boolean shouldDoFinalShutdown = true;
try {
while (_running) {
Frame frame = _frameHandler.readFrame();
// 循环读取来自服务器的消息
readFrame(frame);
}
} catch (Throwable ex) {
if (ex instanceof InterruptedException) {
// loop has been interrupted during shutdown,
// no need to do it again
shouldDoFinalShutdown = false;
} else {
handleFailure(ex);
}
} finally {
if (shouldDoFinalShutdown) {
doFinalShutdown();
}
}
}
}