1.消费端消费消息原理

   ActiveMQ消费端,有两种方法可以来接收消息:

       ①使用同步阻塞的MessageConsumer.receive( )方法;

       ②使用消息监听器MessageListener来实时监听消费消息,通过consumer.setMessageListener(messageListener)来设置。

注意:在同一个会话中,以上两种方法不能同时工作。也就是说不能针对不同的消息来采用不同的接收方式,否则会抛出异常。至于为什么这么做,最大的原因还是在事务性会话中,两种消费模式的情况下,事务的处理不是很好管控。

2.ActiveMQ消息消费流程图

activemq 发送对象信息 activemq怎么保证消息成功消费_sed

分析入口:消息消费,调用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