1.消费端消费消息原理
ActiveMQ消费端,有两种方法可以来接收消息:
①使用同步阻塞的MessageConsumer.receive( )方法;
②使用消息监听器MessageListener来实时监听消费消息,通过consumer.setMessageListener(messageListener)来设置。
注意:在同一个会话中,以上两种方法不能同时工作。也就是说不能针对不同的消息来采用不同的接收方式,否则会抛出异常。至于为什么这么做,最大的原因还是在事务性会话中,两种消费模式的情况下,事务的处理不是很好管控。
2.ActiveMQ消息消费流程图

分析入口:消息消费,调用MessageConsumer.receive()方法来作为一个入口
流程解析
1. 会去判断 prefetchSize 和 unconsumedMessages;
2. 如果为空,则会发起一个pull命令,去调用transport通道;
3. 通过传输层,发送一个pull命令至Broker上;
4. Broker会给transport一个push消息;
5. 通过unconsumed队列去dequeue读取消息;
6. 如果队列为空,将会阻塞在那里;
7. 什么时候接触阻塞?(第4步)当ActiveMQ 通过transport通道push消息过来之后,会有一个enqueue(入队)的过程,服务端会把数据通过传输层push到unconsumedMessages队列中;
8. 当unconsumedMessages队列中有消息之后,解除阻塞,开始消费;
9. 如果unconsumed队列不为空的话,此时会拿到一个MessageDispatch的对象(这是一个消息分发对象);
10. 从MessageDispatch中获取到一个message;
11. 此时会调用beforeMessageIsConsumed( ) 和 afterMessageIsConsumed( )两个方法,将message添加到delivered队列;
12. 然后,发起一个MessageAck的操作,返回一个ACK标识;
13. 返回一个ACK标识之后,会做两件事情:
13.1 会异步的发起一个ACK调度,发送ack给到broker,告诉broker当前消息已经被消费完;
13.2 同时会将message返回给consumer.receive()接收消息。
3.ActiveMQ消息消费源码分析
3.1 调用MessageConsumer.receive( )方法
public Message receive() throws JMSException {
//检查当前的session会话状态。如果session已经关闭,则抛出异常
this.checkClosed();
//检查receive和MessageListener是否同时配置在当前的会话中
this.checkMessageListener();
//【跳转至步骤3.2】如果PrefetchSize为0 & 并且unconsumerMessage为空,则发起pull命令
this.sendPullCommand(0L);
//【跳转至步骤3.4】通过dequeue()方法获取一个消息
MessageDispatch md = this.dequeue(-1L);
if (md == null) {
return null;
} else {
//【跳转至步骤3.6】拿到MessageDispatch对象后,做消费消息之前的一些准备工作
this.beforeMessageIsConsumed(md);
//【跳转至步骤3.7】做消息应答操作
this.afterMessageIsConsumed(md, false);//发送ACK给到broker
//【步骤13.2】
return this.createActiveMQMessage(md);//获取消息并返回
}
}3.2 向服务端(Broker)异步发送pull命令,来获取消息(前提是满足①prefetchSize=0 && ②unconsumedMessages为空)
protected void sendPullCommand(long timeout) throws JMSException {
//【跳转至步骤3.3】清理已经分发的消息列表deliveredMessages
this.clearDeliveredList();
//unconsumedMessage表示未消费的消息队列,这里面预读取的消息大小为prefetchSize的值
if (this.info.getCurrentPrefetchSize() == 0 && this.unconsumedMessages.isEmpty()) {
MessagePull messagePull = new MessagePull();
messagePull.configure(this.info);
messagePull.setTimeout(timeout);
this.session.asyncSendPacket(messagePull);//向服务端异步发送pull指令
}
}3.3 清理已经分发的消息列表
private void clearDeliveredList() {
if (this.clearDeliveredList) {
//deliveredMessages,存储【分发给消费者但还未消费的】消息列表
synchronized(this.deliveredMessages) {
if (this.clearDeliveredList) {
if (!this.deliveredMessages.isEmpty()) {
Iterator var2;
MessageDispatch md;
//如果session会话是事务的,则会遍历deliveredMessage中的消息放入到previouslyDeliveredMessage中来做重发
if (this.session.isTransacted()) {
if (this.previouslyDeliveredMessages == null) {
this.previouslyDeliveredMessages = new ActiveMQMessageConsumer.PreviouslyDeliveredMap(this.session.getTransactionContext().getTransactionId());
}
var2 = this.deliveredMessages.iterator();
while(var2.hasNext()) {
md = (MessageDispatch)var2.next();
this.previouslyDeliveredMessages.put(md.getMessage().getMessageId(), false);
}
LOG.debug("{} tracking existing transacted {} delivered list ({}) on transport interrupt", new Object[]{this.getConsumerId(), this.previouslyDeliveredMessages.transactionId, this.deliveredMessages.size()});
} else { //如果session会话是非事务的,根据ACK的模式来选择不同的应答操作
if (this.session.isClientAcknowledge()) {
LOG.debug("{} rolling back delivered list ({}) on transport interrupt", this.getConsumerId(), this.deliveredMessages.size());
if (!this.info.isBrowser()) {
var2 = this.deliveredMessages.iterator();
while(var2.hasNext()) {
md = (MessageDispatch)var2.next();
this.session.connection.rollbackDuplicate(this, md.getMessage());
}
}
}
LOG.debug("{} clearing delivered list ({}) on transport interrupt", this.getConsumerId(), this.deliveredMessages.size());
this.deliveredMessages.clear();
this.pendingAck = null;
}
}
this.clearDeliveredList = false;
}
}
}
}3.4 从unconsumedMessages队列中dequeue消息(unchonsumedMessages队列里的值什么时候有的?)
建议:请先关注消费端消息消费主线。如需了解unconsumedMessages队列中值的来源,请看完主线后再查看本文第4段---unconsumedMessages源码分析。
private MessageDispatch dequeue(long timeout) throws JMSException {
try {
long deadline = 0L;
if (timeout > 0L) {
deadline = System.currentTimeMillis() + timeout;
}
while(true) {
while(true) {
//这个队列的dequeue()方法实现,有两种分发渠道:
//一种是先进先出的分发渠道:FifoMessageDispatchChannel
//另一种是简单优先级队列分发渠道:SimplePriorityMessageDispatchChannel
//至于为什么要存在这样一个消息分发通道,大家可以想象一下,如果消费者每次去消费完一个消息以后再去Broker
//拿消息,效率是比较低的。所以通过这样的设计可以允许session能够一次性将多条消息分发给一个消费者
//【跳转至步骤3.5】
MessageDispatch md = this.unconsumedMessages.dequeue(timeout);
//如果message消息为空
if (md == null) {
if (timeout <= 0L || this.unconsumedMessages.isClosed()) {
if (this.failureError != null) {
throw JMSExceptionSupport.create(this.failureError);
} else {
return null;
}
}
timeout = Math.max(deadline - System.currentTimeMillis(), 0L);
} else {
if (md.getMessage() == null) {
return null;
}
//如果消息过期
if (this.consumeExpiredMessage(md)) {
LOG.debug("{} received expired message: {}", this.getConsumerId(), md);
this.beforeMessageIsConsumed(md);
this.afterMessageIsConsumed(md, true);
if (timeout > 0L) {
timeout = Math.max(deadline - System.currentTimeMillis(), 0L);
}
//重新发起一个pull命令
this.sendPullCommand(timeout);
} else {
//判断是否是重发消息
if (!this.redeliveryExceeded(md)) {
if (LOG.isTraceEnabled()) {
LOG.trace(this.getConsumerId() + " received message: " + md);
}
//返回一个MessageDispatch消息对象
return md;
}
LOG.debug("{} received with excessive redelivered: {}", this.getConsumerId(), md);
this.posionAck(md, "Dispatch[" + md.getRedeliveryCounter() + "] to " + this.getConsumerId() + " exceeds redelivery policy limit:" + this.redeliveryPolicy);
if (timeout > 0L) {
timeout = Math.max(deadline - System.currentTimeMillis(), 0L);
}
//或者重新发起pull命令
this.sendPullCommand(timeout);
//【回退至步骤3.1】
}
}
}
}
} catch (InterruptedException var6) {
Thread.currentThread().interrupt();
throw JMSExceptionSupport.create(var6);
}
}3.5 从unconsumedMessages队列中dequeue消息实现类
//FifoMessageDispatchChannel类中dequeue方法分析
//另一实现类SimplePriorityMessageDispatchChannel类中dequeue方法类似,此处不做分析
public MessageDispatch dequeue(long timeout) throws InterruptedException {
//加锁,保证数据的准确性
synchronized(this.mutex) {
//判断超时时间、队列为空等情况
while(timeout != 0L && !this.closed && (this.list.isEmpty() || !this.running)) {
if (timeout != -1L) {
//等待【阻塞】
this.mutex.wait(timeout);
break;
}
this.mutex.wait();
}
//反之,从队列中拿到第一个结果并返回
return !this.closed && this.running && !this.list.isEmpty() ? (MessageDispatch)this.list.removeFirst() : null;
//【回退至步骤3.4】
}
}3.6 分析beforeMessageIsConsumed()方法,做消费消息之前的一些准备工作
private void beforeMessageIsConsumed(MessageDispatch md) throws JMSException {
md.setDeliverySequenceId(this.session.getNextDeliveryId());
this.lastDeliveredSequenceId = md.getMessage().getMessageId().getBrokerSequenceId();
//判断如果不是延迟消费(Session.DUPS_OK_ACKNOWLEDGE) && destination不是队列Queue
if (!this.isAutoAcknowledgeBatch()) {
//所有消息都会放到deliveredMessages
synchronized(this.deliveredMessages) {
this.deliveredMessages.addFirst(md);
}
//如果是事务处理
if (this.session.getTransacted()) {
if (this.transactedIndividualAck) {
//单条确认
this.immediateIndividualTransactedAck(md);
} else {
//延迟确认(将消息set到pendingAck中,当达到一定的阀值之后,会一次性将消息确认掉(就是:批量确认,能够减少客户端和服务端的网络通信,能够提升新能))
this.ackLater(md, (byte)0);
}
}
//【回退至步骤3.1】
}
}
private boolean isAutoAcknowledgeBatch() {
return this.session.isDupsOkAcknowledge() && !this.getDestination().isQueue();
}这里面主要是做消息消费之前的一些准备工作:
①如果ACK类型不是DUPS_OK_ACKNOWLEDGE或者Queue队列模式(简单来说就是除了Topic和DupAck这两种情况),所有的消息先放到deliveredMessages链表的开头。
②并且如果当前是事务类型的会话,则判断transactedIndividualAck。如果为true,表示单条消息直接返回ack,否则,调用ackLater,批量应答。客户端端在消费消息后暂且不发送ACK,而是把它缓存下来(pendingACK),等到这些消息的条数达到一定阀值时,只需要通过一个ACK指令把它们全部确认。这中批量应答方式,比对每条消息都逐个确认,在性能上要提高很多。
3.7 分析afterMessageIsConsumed()方法,主要做完成消息的确认过程
private void afterMessageIsConsumed(MessageDispatch md, boolean messageExpired) throws JMSException {
if (!this.unconsumedMessages.isClosed()) {
//判断消息是否过期
if (messageExpired) {
//【步骤13.1】
this.acknowledge(md, (byte)6);
this.stats.getExpiredMessageCount().increment();
} else {
this.stats.onMessage();
//非事务类型会话
if (!this.session.getTransacted()) {
//
if (this.isAutoAcknowledgeEach()) {
if (this.deliveryingAcknowledgements.compareAndSet(false, true)) {
//deliveredMessages是在beforeMessageIsConsumed()方法中,未确认消息列表
synchronized(this.deliveredMessages) {
//不为空
if (!this.deliveredMessages.isEmpty()) {
MessageAck ack;
if (this.optimizeAcknowledge) {
++this.ackCounter;
if ((double)(this.ackCounter + this.deliveredCounter) >= (double)this.info.getPrefetchSize() * 0.65D || this.optimizeAcknowledgeTimeOut > 0L && System.currentTimeMillis() >= this.optimizeAckTimestamp + this.optimizeAcknowledgeTimeOut) {
ack = this.makeAckForAllDeliveredMessages((byte)2);
if (ack != null) {
this.deliveredMessages.clear();
this.ackCounter = 0;
this.session.sendAck(ack);
this.optimizeAckTimestamp = System.currentTimeMillis();
}
if (this.pendingAck != null && this.deliveredCounter > 0) {
this.session.sendAck(this.pendingAck);
this.pendingAck = null;
this.deliveredCounter = 0;
}
}
} else {
ack = this.makeAckForAllDeliveredMessages((byte)2);
if (ack != null) {
this.deliveredMessages.clear();
this.session.sendAck(ack);
}
}
}
}
this.deliveryingAcknowledgements.set(false);
}
} else if (this.isAutoAcknowledgeBatch()) {
this.ackLater(md, (byte)2);
} else {
if (!this.session.isClientAcknowledge() && !this.session.isIndividualAcknowledge()) {
throw new IllegalStateException("Invalid session state.");
}
boolean messageUnackedByConsumer = false;
synchronized(this.deliveredMessages) {
messageUnackedByConsumer = this.deliveredMessages.contains(md);
}
if (messageUnackedByConsumer) {
this.ackLater(md, (byte)0);
}
}
}
}
}
}这方法里面主要是做消息应答操作,做了以下几个操作:
Ø 如果消息过期,则返回消息过期的ack;
Ø 如果是事务类型的会话,则不做任何处理;
Ø 如果是AUTOACK或者(DUPS_OK_ACK且是队列Queue),并且是优化ack操作,则走批量确认ack;
Ø 如果是DUPS_OK_ACK,则走ackLater逻辑;
Ø 如果是CLIENT_ACK,则执行ackLater。
ActiveMQ消费端消息消费源码分析END,以下为unconsumedMessage队列值的来源源码分析
4.unconsumedMessages源码分析(unconsumedMessages队列值的来源)
unconsumedMessages队列中数据的获取过程,是在ActiveMQ创建连接的过程中获取的。接下来我们可以看看ActiveMQ创建连接的过程,即:ActiveMQConnectionFactory.createConnection()方法里面,到底做了哪些事情。
4.1 ActiveMQ创建连接的过程
//1.
public Connection createConnection() throws JMSException {
return this.createActiveMQConnection();
}
//2.
protected ActiveMQConnection createActiveMQConnection() throws JMSException {
return this.createActiveMQConnection(this.userName, this.password);
}
//3.
protected ActiveMQConnection createActiveMQConnection(String userName, String password) throws JMSException {
if (this.brokerURL == null) {
throw new ConfigurationException("brokerURL not set.");
} else {
ActiveMQConnection connection = null;
try {
//3.1 通过createTransport(),动态创建一个协议;
Transport transport = this.createTransport();
//3.2 创建一个连接;
connection = this.createActiveMQConnection(transport, this.factoryStats);
connection.setUserName(userName);
connection.setPassword(password);
this.configureConnection(connection);
//3.3 通过transport.start()开始传输。
transport.start();
if (this.clientID != null) {
connection.setDefaultClientID(this.clientID);
}
return connection;
} catch (JMSException var8) {
try {
connection.close();
} catch (Throwable var7) {
}
throw var8;
} catch (Exception var9) {
try {
connection.close();
} catch (Throwable var6) {
}
throw JMSExceptionSupport.create("Could not connect to broker URL: " + this.brokerURL + ". Reason: " + var9, var9);
}
}
}4.2 transport.start( )开始消息传输
在ActiveMQ消息发送的时候,我们已经知道transport是一个链式的调用,是一个多层包装的对象。最终链式调用包装后结构如下:ResponseCorrelator(MutexTransport(WireFormatNegotiator(InactivityMonitor(TcpTransport()))))
最终调用TcpTransport.start()方法,然而TcpTransport这个类中并没有start()方法,而是调用父类ServiceSupport中的start()方法。所以此处调用ServiceSupport.start()方法。
//transport.start()消息传输
public void start() throws Exception {
if (this.started.compareAndSet(false, true)) {
boolean success = false;
this.stopped.set(false);
try {
this.preStart();
//1.调用doStart()方法,此处会去调用TcpTransport.doStart()方法
this.doStart();
success = true;
} finally {
this.started.set(success);
}
Iterator var2 = this.serviceListeners.iterator();
while(var2.hasNext()) {
ServiceListener l = (ServiceListener)var2.next();
l.started(this);
}
}
}
//调用doStart()方法
protected void doStart() throws Exception {
this.connect();
this.stoppedLatch.set(new CountDownLatch(1));
//2.执行super.doStart()方法
super.doStart();
}
//super即调用TransportThreadSupport.doStart()方法
protected void doStart() throws Exception {
//创建了一个线程,调用子类的run方法,也就是TcpTransport.run()方法
this.runner = new Thread((ThreadGroup)null, this, "ActiveMQ Transport: " + this.toString(), this.stackSize);
this.runner.setDaemon(this.daemon);
this.runner.start();
}4.3 TcpTransport.run()方法的调用
public void run() {
LOG.trace("TCP consumer thread for " + this + " starting");
this.runnerThread = Thread.currentThread();
try {
//通过线程调用,从socket中读取数据包.只要TcpTransport传输没有停止,就会不断去调用doRun()方法
while(!this.isStopped()) {
this.doRun();
}
} catch (IOException var7) {
((CountDownLatch)this.stoppedLatch.get()).countDown();
this.onException(var7);
} catch (Throwable var8) {
((CountDownLatch)this.stoppedLatch.get()).countDown();
IOException ioe = new IOException("Unexpected error occurred: " + var8);
ioe.initCause(var8);
this.onException(ioe);
} finally {
((CountDownLatch)this.stoppedLatch.get()).countDown();
}
}4.4 TcpTransport.doRun()方法的调用
protected void doRun() throws IOException {
try {
//【步骤4.4.1】doRun()方法中,通过调用readCommand()方法来不停的读取数据
Object command = this.readCommand();
//【步骤4.4.2】(重要)读取数据后,然后将数据传入doConsume()方法,用来消费消息
this.doConsume(command);
} catch (SocketTimeoutException var2) {
} catch (InterruptedIOException var3) {
}
}4.4.1 readCommand()方法,来对数据进行格式化处理
//readCommand()方法
protected Object readCommand() throws IOException {
//通过wireFormat对数据进行格式化,可以认为这是一个反序列化的过程
return this.wireFormat.unmarshal(this.dataIn);
}分析到这,我们差不多明白了传输层的主要工作就是:获得数据并且把数据转换为对象,再把对象传给ActiveMQConnection
4.4.2 TransportSupport.doConsume()方法,用来消费消息
public void doConsume(Object command) {
if (command != null) {
if (this.transportListener != null) {
this.transportListener.onCommand(command);
} else {
LOG.error("No transportListener available to process inbound command: " + command);
}
}
}TransportSupport类中,唯一的成员变量是TransportListener transportListener;这也就意味着一个Transport类支持绑定一个传送监听器类,传送监听器接口TransportListener 最重要的方法就是void onCommand(Object command);它用来处理命令。那么这个transportListener是在哪里赋值的呢?
4.5 transportListener监听器赋值问题,我们再回到ActiveMQConnection创建ActiveMQ连接处分析
//1.
public Connection createConnection() throws JMSException {
return this.createActiveMQConnection();
}
//2.
protected ActiveMQConnection createActiveMQConnection() throws JMSException {
return this.createActiveMQConnection(this.userName, this.password);
}
//3.
protected ActiveMQConnection createActiveMQConnection(String userName, String password) throws JMSException {
if (this.brokerURL == null) {
throw new ConfigurationException("brokerURL not set.");
} else {
ActiveMQConnection connection = null;
try {
Transport transport = this.createTransport();
//(重点)在此处创建一个ActiveMQ连接;
connection = this.createActiveMQConnection(transport, this.factoryStats);
connection.setUserName(userName);
connection.setPassword(password);
this.configureConnection(connection);
transport.start();
if (this.clientID != null) {
connection.setDefaultClientID(this.clientID);
}
return connection;
} catch (JMSException var8) {
......省略部分代码......
}
}
}
//4.
protected ActiveMQConnection createActiveMQConnection(Transport transport, JMSStatsImpl stats) throws Exception {
//(重点)调用ActiveMQConnection的构造方法
ActiveMQConnection connection = new ActiveMQConnection(transport, this.getClientIdGenerator(), this.getConnectionIdGenerator(), stats);
return connection;
}
//5.ActiveMQConnection的构造方法
protected ActiveMQConnection(final Transport transport, IdGenerator clientIdGenerator, IdGenerator connectionIdGenerator, JMSStatsImpl factoryStats) throws Exception {
this.maxThreadPoolSize = DEFAULT_THREAD_POOL_SIZE;
this.rejectedTaskHandler = null;
this.trustedPackages = new ArrayList();
this.trustAllPackages = false;
//传参设置
this.transport = transport;
this.clientIdGenerator = clientIdGenerator;
this.factoryStats = factoryStats;
this.executor = new ThreadPoolExecutor(1, 1, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "ActiveMQ Connection Executor: " + transport);
return thread;
}
});
String uniqueId = connectionIdGenerator.generateId();
this.info = new ConnectionInfo(new ConnectionId(uniqueId));
this.info.setManageable(true);
this.info.setFaultTolerant(transport.isFaultTolerant());
this.connectionSessionId = new SessionId(this.info.getConnectionId(), -1L);
//设置transportListener为this(this就是ActiveMQConnection类,本类)
//会在connection创建连接时,去监听服务端给的command命令
//此处传递ActiveMQConnection类,因为ActiveMQConnection是TransportListener接口的实现类之一
this.transport.setTransportListener(this);
this.stats = new JMSConnectionStatsImpl(this.sessions, this instanceof XAConnection);
this.factoryStats.addConnection(this);
this.timeCreated = System.currentTimeMillis();
this.connectionAudit.setCheckForDuplicates(transport.isFaultTolerant());
}在创建ActiveMQ连接的时候,除了会创建ActiveMQConnection外,还会完成消息监听TransportListener的设置,还会完成线程池执行器ThreadPoolExecutor的初始化;
消息监听器 transportListener 类的初始化,我们已经知道是在创建ActiveMQConnection连接的时候完成的,现在我们回到【步骤4.4.2】中,来看看transportListener.onCommand()方法的具体实现吧
4.6 transportListener.onCommand()方法分析(onCommand方法是一个重要方法)
这里面会针对不同的消息做分发,比如我们传入的command是MessageDispatch,那么这个command的visit()方法就会调用processMessageDispatch()方法
MessageDispatch md = this.dequeue(-1L); 传入的 command 是 MessageDispatch,所以我们只需要关注processMessageDispatch()方法,在这个方法中,只是简单的调用了 ActiveMQSession 的 dispatch 方法来分发处理消息。
备注:此处的 command.visit( ) 方法,这里使用的是适配器模式,如果 command 传过来是一个MessageDispatch,那么它只会调用 processMessageDispatch( ) 方法,其他的方法它并不会去执行。
public void onCommand(Object o) {
final Command command = (Command)o;
if (!this.closed.get() && command != null) {
try {
command.visit(new CommandVisitorAdapter() {
public Response processMessageDispatch(MessageDispatch md) throws Exception {
ActiveMQConnection.this.waitForTransportInterruptionProcessingToComplete();
ActiveMQDispatcher dispatcher = (ActiveMQDispatcher)ActiveMQConnection.this.dispatchers.get(md.getConsumerId());
if (dispatcher != null) {
Message msg = md.getMessage();
if (msg != null) {
msg = msg.copy();
msg.setReadOnlyBody(true);
msg.setReadOnlyProperties(true);
msg.setRedeliveryCounter(md.getRedeliveryCounter());
msg.setConnection(ActiveMQConnection.this);
msg.setMemoryUsage((MemoryUsage)null);
md.setMessage(msg);
}
//调用ActiveMQSession中的dispatch()方法来分发处理消息
dispatcher.dispatch(md);
} else {
ActiveMQConnection.LOG.debug("{} no dispatcher for {} in {}", new Object[]{this, md, ActiveMQConnection.this.dispatchers});
}
return null;
}
public Response processProducerAck(ProducerAck pa) throws Exception {
if (pa != null && pa.getProducerId() != null) {
ActiveMQMessageProducer producer = (ActiveMQMessageProducer)ActiveMQConnection.this.producers.get(pa.getProducerId());
if (producer != null) {
producer.onProducerAck(pa);
}
}
return null;
}
......省略部分代码......
});
} catch (Exception var5) {
this.onClientInternalException(var5);
}
}
Iterator iter = this.transportListeners.iterator();
while(iter.hasNext()) {
TransportListener listener = (TransportListener)iter.next();
listener.onCommand(command);
}
}4.7 进入ActiveMQSession.dispatch( )方法,来完成消息分发操作
public void dispatch(MessageDispatch messageDispatch) {
try {
//executor 这个对象,其实是一个成员对象 ActiveMQSessionExecutor,专门负责来处理消息分发
this.executor.execute(messageDispatch);
} catch (InterruptedException var3) {
Thread.currentThread().interrupt();
this.connection.onClientInternalException(var3);
}
}4.7.1 执行ActiveMQSessionExecutor.execute( )方法,来处理消息的分发
void execute(MessageDispatch message) throws InterruptedException {
if (!this.startedOrWarnedThatNotStarted) {
ActiveMQConnection connection = this.session.connection;
long aboutUnstartedConnectionTimeout = connection.getWarnAboutUnstartedConnectionTimeout();
if (!connection.isStarted() && aboutUnstartedConnectionTimeout >= 0L) {
long elapsedTime = System.currentTimeMillis() - connection.getTimeCreated();
if (elapsedTime > aboutUnstartedConnectionTimeout) {
LOG.warn("Received a message on a connection which is not yet started. Have you forgotten to call Connection.start()? Connection: " + connection + " Received: " + message);
this.startedOrWarnedThatNotStarted = true;
}
} else {
this.startedOrWarnedThatNotStarted = true;
}
}
//如果会话不是异步分发 && 没有使用sessionPool分发,则调用dispatch来分发消息
if (!this.session.isSessionAsyncDispatch() && !this.dispatchedBySessionPool) {
this.dispatch(message);
} else {
//将消息直接放入到队列里
this.messageQueue.enqueue(message);
//【跳转至步骤4.8】完成异步分发过程
this.wakeup();
}
}4.7 执行ActiveMQSessionExecutor.wakeup( )方法,完成异步分发过程的处理
①异步分发:ActiveMQSessionExecutor类实现了Task接口,则需要实现Task接口的 iterate 方法,然后通过taskRunner.wakeup( ) 方法来获取任务完成调度,通过 wakeup( ) 会触发重写的 iterate( ) 方法,来执行我们的消息分发操作【步骤4.8为异步分发全过程】
②同步分发:直接执行重写的 iterate( ) 方法,来完成消息的分发操作。【步骤4.9为异步分发全过程】
public void wakeup() {
//进一步验证是否使用sessionPool
if (!this.dispatchedBySessionPool) {
//进一步判断session会话是否为异步分发
if (this.session.isSessionAsyncDispatch()) {//异步分发
try {
TaskRunner taskRunner = this.taskRunner;
if (taskRunner == null) {
synchronized(this) {
if (this.taskRunner == null) {
if (!this.isRunning()) {
return;
}
//通过 TaskRunnerFactory 创建了一个任务运行类 taskRunner。这里把自己作为一个task传入到createTaskRunner中
//说明当前的类一定是实现了Task接口的。简单来说,就是通过线程池去执行一个任务,来完成异步调度
this.taskRunner = this.session.connection.getSessionTaskRunner().createTaskRunner(this, "ActiveMQ Session: " + this.session.getSessionId());
}
taskRunner = this.taskRunner;
}
}
//然后调用wakeup()方法完成异步分发操作。通过 wakeup() 会触发重写的 iterate() 方法
taskRunner.wakeup();
} catch (InterruptedException var5) {
Thread.currentThread().interrupt();
}
} else {
//同步分发
while(true) {
if (this.iterate()) {
continue;
}
}
}
}
}异步分发)触发ActiveMQSessionExecutor中的iterate( )方法
这个方法里面做了如下两件事情:
Ø 把消费者监听的所有消息,转存到待消费队列中;
Ø 如果messageQueue还存在遗留消息,同样把消息分发出去。
public boolean iterate() {
Iterator var1 = this.session.consumers.iterator();
ActiveMQMessageConsumer consumer;
do {
if (!var1.hasNext()) {
//把消费者监听的所有消息,转存到待消费队列中;
MessageDispatch message = this.messageQueue.dequeueNoWait();
if (message == null) {
return false;
}
//如果messageQueue还存在遗留消息,同样把消息分发出去
this.dispatch(message);
return !this.messageQueue.isEmpty();
}
consumer = (ActiveMQMessageConsumer)var1.next();
} while(!consumer.iterate());//再次执行consumer.iterate()方法
return true;
}4.8.1 执行consumer.iterate( )方法
public boolean iterate() {
MessageListener listener = (MessageListener)this.messageListener.get();
//如果listener不为空的话,直接从unconsumedMessages队列中获得一个消息
if (listener != null) {
MessageDispatch md = this.unconsumedMessages.dequeueNoWait();
//如果获得的消息为空,则再次通过dispatch()方法,分发消息
if (md != null) {
//【跳转至步骤4.8.2】开始分发消息
this.dispatch(md);
return true;
}
}
return false;
}4.8.2 执行ActiveMQMessageConsumer.dispatch()再次分发消息
public void dispatch(MessageDispatch md) {
MessageListener listener = (MessageListener)this.messageListener.get();
try {
this.clearMessagesInProgress();
this.clearDeliveredList();
synchronized(this.unconsumedMessages.getMutex()) {
if (!this.unconsumedMessages.isClosed()) {
if (!this.info.isBrowser() && this.session.connection.isDuplicate(this, md.getMessage())) {
......部分代码省略......
} else if (listener != null && this.unconsumedMessages.isRunning()) {
......部分代码省略......
} else {
if (!this.unconsumedMessages.isRunning()) {
this.session.connection.rollbackDuplicate(this, md.getMessage());
}
if (md.getMessage() == null) {
//在此处你就会看到,将消息enqueue到unconsumedMessages队列中了
//这就是unconsumedMessages队列中消息的由来
this.unconsumedMessages.enqueue(md);
} else if (!this.consumeExpiredMessage(md)) {
//在此处你就会看到,将消息enqueue到unconsumedMessages队列中了
this.unconsumedMessages.enqueue(md);
if (this.availableListener != null) {
this.availableListener.onMessageAvailable(this);
}
} else {
......部分代码省略......
}
}
}
}
......部分代码省略......
} catch (Exception var9) {
this.session.connection.onClientInternalException(var9);
}
}同步分发)直接调用ActiveMQSessionExecutor中的dispatch()方法
void dispatch(MessageDispatch message) {
Iterator var2 = this.session.consumers.iterator();
while(var2.hasNext()) {
ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer)var2.next();
ConsumerId consumerId = message.getConsumerId();
if (consumerId.equals(consumer.getConsumerId())) {
//同步分发,直接调用dispatch()方法。此方法同异步分发dispatch()方法一样,再次不做重复,
//如需了解,请查看【步骤4.8.2】中dispatch()分发
consumer.dispatch(message);
break;
}
}
}至此,unconsumedMessages队列中的值的由来,到此也就告一段落了。此时unconsumedMessages队列有消息了,也就可以【跳转至步骤3.4】继续了解消息的消费过程了
END
















