ActiveMQ连接工厂、连接详解: http://donald-draper.iteye.com/blog/2348070
ActiveMQ会话初始化: http://donald-draper.iteye.com/blog/2348341
ActiveMQ生产者: http://donald-draper.iteye.com/blog/2348381
ActiveMQ消费者: http://donald-draper.iteye.com/blog/2348389
ActiveMQ启动过程详解 :http://donald-draper.iteye.com/blog/2348399
ActiveMQ Broker发送消息给消费者过程详解: http://donald-draper.iteye.com/blog/2348440
Spring与ActiveMQ的集成: http://donald-draper.iteye.com/blog/2347638
Spring与ActiveMQ的集成详解一: http://donald-draper.iteye.com/blog/2348449
Spring与ActiveMQ的集成详解二: http://donald-draper.iteye.com/blog/2348461
上一篇我们讲了生产者,今天来说一下消费者,从下面这段开始
// Destination :消息的目的地;消息发送给谁. Topic destination=session.createTopic(tname); // 消费者,消息接收者 MessageConsumer consumer = session.createConsumer(destination);
//ActiveMQSession创建消费者
public MessageConsumer createConsumer(Destination destination) throws JMSException { return createConsumer(destination, (String)null); } public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException { return createConsumer(destination, messageSelector, false); } public MessageConsumer createConsumer(Destination destination, MessageListener messageListener) throws JMSException { return createConsumer(destination, null, messageListener); } public MessageConsumer createConsumer(Destination destination, String messageSelector, MessageListener messageListener) throws JMSException { return createConsumer(destination, messageSelector, false, messageListener); } public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal) throws JMSException { return createConsumer(destination, messageSelector, noLocal, null); } public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal, MessageListener messageListener) throws JMSException { checkClosed(); if(destination instanceof CustomDestination) { CustomDestination customDestination = (CustomDestination)destination; return customDestination.createConsumer(this, messageSelector, noLocal); } //从连接后去获取消息策略 ActiveMQPrefetchPolicy prefetchPolicy = connection.getPrefetchPolicy(); int prefetch = 0; if(destination instanceof Topic) prefetch = prefetchPolicy.getTopicPrefetch(); else prefetch = prefetchPolicy.getQueuePrefetch(); ActiveMQDestination activemqDestination = ActiveMQMessageTransformation.transformDestination(destination); //创建消费者 return new ActiveMQMessageConsumer(this, getNextConsumerId(), activemqDestination, null, messageSelector, prefetch, prefetchPolicy.getMaximumPendingMessageLimit(), noLocal, false, isAsyncDispatch(), messageListener); }
public class ActiveMQMessageConsumer implements MessageAvailableConsumer, StatsCapable, ActiveMQDispatcher { protected final ActiveMQSession session; protected final ConsumerInfo info;//消费者信息 protected final MessageDispatchChannel unconsumedMessages;//消息分发通道(没消费的消息) protected final LinkedList deliveredMessages = new LinkedList();//传输消息队列 private PreviouslyDeliveredMap previouslyDeliveredMessages; private int deliveredCounter;//传输消息计数器 private int additionalWindowSize; private long redeliveryDelay;//消息传输延时 private int ackCounter;//消息回复计时器 private int dispatchedCount;//消息分发计时器 private final AtomicReference messageListener = new AtomicReference();//消息监听器引用 private final JMSConsumerStatsImpl stats;//消费者状态信息管理器 private final String selector;选择器 private boolean synchronizationRegistered; private final AtomicBoolean started = new AtomicBoolean(false);//启动状态 private MessageAvailableListener availableListener; private RedeliveryPolicy redeliveryPolicy;//传输策略 private boolean optimizeAcknowledge; private final AtomicBoolean deliveryingAcknowledgements = new AtomicBoolean(); private ExecutorService executorService;//执行器 private MessageTransformer transformer; private boolean clearDeliveredList; AtomicInteger inProgressClearRequiredFlag; private MessageAck pendingAck;//消息回复 private long lastDeliveredSequenceId; private IOException failureError; private long optimizeAckTimestamp; private long optimizeAcknowledgeTimeOut; private long optimizedAckScheduledAckInterval; private Runnable optimizedAckTask;//消息回复优化任务 private long failoverRedeliveryWaitPeriod;//当Master宕机时,消息传输等待时间 private boolean transactedIndividualAck; private boolean nonBlockingRedelivery;//是否非阻塞传输 private boolean consumerExpiryCheckEnabled; public ActiveMQMessageConsumer(ActiveMQSession session, ConsumerId consumerId, ActiveMQDestination dest, String name, String selector, int prefetch, int maximumPendingMessageCount, boolean noLocal, boolean browser, boolean dispatchAsync, MessageListener messageListener) throws JMSException { inProgressClearRequiredFlag = new AtomicInteger(0); lastDeliveredSequenceId = -1L; optimizeAckTimestamp = System.currentTimeMillis(); optimizeAcknowledgeTimeOut = 0L; optimizedAckScheduledAckInterval = 0L; failoverRedeliveryWaitPeriod = 0L; transactedIndividualAck = false; nonBlockingRedelivery = false; consumerExpiryCheckEnabled = true; if(dest == null) throw new InvalidDestinationException("Don't understand null destinations"); if(dest.getPhysicalName() == null) throw new InvalidDestinationException("The destination object was not given a physical name."); if(dest.isTemporary()) { String physicalName = dest.getPhysicalName(); if(physicalName == null) throw new IllegalArgumentException((new StringBuilder()).append("Physical name of Destination should be valid: ").append(dest).toString()); String connectionID = session.connection.getConnectionInfo().getConnectionId().getValue(); if(physicalName.indexOf(connectionID) < 0) throw new InvalidDestinationException("Cannot use a Temporary destination from another Connection"); if(session.connection.isDeleted(dest)) throw new InvalidDestinationException("Cannot use a Temporary destination that has been deleted"); if(prefetch < 0) throw new JMSException("Cannot have a prefetch size less than zero"); } //配置消息分发通道 if(session.connection.isMessagePrioritySupported()) unconsumedMessages = new SimplePriorityMessageDispatchChannel(); else unconsumedMessages = new FifoMessageDispatchChannel(); this.session = session; //获取连接重新传输策略 redeliveryPolicy = session.connection.getRedeliveryPolicyMap().getEntryFor(dest); setTransformer(session.getTransformer()); info = new ConsumerInfo(consumerId); info.setExclusive(this.session.connection.isExclusiveConsumer()); info.setClientId(this.session.connection.getClientID()); info.setSubscriptionName(name); info.setPrefetchSize(prefetch); info.setCurrentPrefetchSize(prefetch); info.setMaximumPendingMessageLimit(maximumPendingMessageCount); info.setNoLocal(noLocal); info.setDispatchAsync(dispatchAsync); info.setRetroactive(this.session.connection.isUseRetroactiveConsumer()); info.setSelector(null); if(dest.getOptions() != null) { Map options = IntrospectionSupport.extractProperties(new HashMap(dest.getOptions()), "consumer."); IntrospectionSupport.setProperties(info, options); if(options.size() > 0) { String msg = (new StringBuilder()).append("There are ").append(options.size()).append(" consumer options that couldn't be set on the consumer.").append(" Check the options are spelled correctly.").append(" Unknown parameters=[").append(options).append("].").append(" This consumer cannot be started.").toString(); LOG.warn(msg); throw new ConfigurationException(msg); } } info.setDestination(dest); info.setBrowser(browser); if(selector != null && selector.trim().length() != 0) { SelectorParser.parse(selector); info.setSelector(selector); this.selector = selector; } else if(info.getSelector() != null) { SelectorParser.parse(info.getSelector()); this.selector = info.getSelector(); } else { this.selector = null; } //创建消费者状态管理器 stats = new JMSConsumerStatsImpl(session.getSessionStats(), dest); optimizeAcknowledge = session.connection.isOptimizeAcknowledge() && session.isAutoAcknowledge() && !info.isBrowser(); if(optimizeAcknowledge) { optimizeAcknowledgeTimeOut = session.connection.getOptimizeAcknowledgeTimeOut(); setOptimizedAckScheduledAckInterval(session.connection.getOptimizedAckScheduledAckInterval()); } info.setOptimizedAcknowledge(optimizeAcknowledge); failoverRedeliveryWaitPeriod = session.connection.getConsumerFailoverRedeliveryWaitPeriod(); nonBlockingRedelivery = session.connection.isNonBlockingRedelivery(); transactedIndividualAck = session.connection.isTransactedIndividualAck() || nonBlockingRedelivery || session.connection.isMessagePrioritySupported(); consumerExpiryCheckEnabled = session.connection.isConsumerExpiryCheckEnabled(); if(messageListener != null) //设置消息监听器 setMessageListener(messageListener); try { //将消费者添加到会话 this.session.addConsumer(this); //发送消费者信息给broker this.session.syncSendPacket(info); } catch(JMSException e) { this.session.removeConsumer(this); throw e; } //如果连接启动,则启动消费者 if(session.connection.isStarted()) start(); } }
创建消费者就是初始化消费者,传输延时,选择器,消息监听器,消息重传策略,并把消费者信息发送给broker,同时将消费者添加到会话中,启动会话执行器,通知消息者消费消息;
这个我们在会话启动篇又说,这里我们简单地说一下:
//启动消费者
public void start() throws JMSException { if(unconsumedMessages.isClosed()) { return; } else { started.set(true); //启动消息通道,通知消息通道可以发送未消费的消息给消息者 unconsumedMessages.start(); //通过会话执行器唤醒消费者,消费消息 session.executor.wakeup(); return; } }
unconsumedMessages我们以先进先出消息分发通道来讲FifoMessageDispatchChannel
,还有一种是基于消息优先级的这里就不说了前文以说
public class FifoMessageDispatchChannel implements MessageDispatchChannel { private final Object mutex = new Object(); private final LinkedList list = new LinkedList(); private boolean closed; private boolean running; public void start() { synchronized(mutex) { //通知所有等待分发消息互斥量的线程 running = true; mutex.notifyAll(); } } }
//唤醒会话执行器
session.executor.wakeup();
下面是我们前文的关于这一句的总结
稍微简单过一下
public class ActiveMQSessionExecutor implements Task { //唤醒消费者,消费消息 public void wakeup() { //this为ActiveMQSessionExecutor, this.taskRunner = session.connection.getSessionTaskRunner().createTaskRunner(this, (new StringBuilder()).append("ActiveMQ Session: ").append(session.getSessionId()).toString()); taskRunner = this.taskRunner; //唤醒任务线程,taskRunner实际为PooledTaskRunner taskRunner.wakeup(); } }
class PooledTaskRunner implements TaskRunner { public PooledTaskRunner(Executor executor, final Task task, int maxIterationsPerRun) { this.executor = executor; this.maxIterationsPerRun = maxIterationsPerRun; this.task = task; runable = new Runnable() { public void run() { runningThread = Thread.currentThread(); //运行任务 runTask(); } final Task val$task; final PooledTaskRunner this$0; { this$0 = PooledTaskRunner.this; task = task1; super(); } }; } } final void runTask() { label0: { synchronized(runable) { queued = false; if(!shutdown) break label0; iterating = false; runable.notifyAll(); } return; } iterating = true; _L1: boolean done = false; int i = 0; do { if(i >= maxIterationsPerRun) break; LOG.trace("Running task iteration {} - {}", Integer.valueOf(i), task); //关键在这一句,task为ActiveMQSessionExecutor if(!task.iterate()) { done = true; break; } i++; } while(true); ... }
再看ActiveMQSessionExecutor
//ActiveMQSessionExecutor
public boolean iterate() { for(Iterator i$ = session.consumers.iterator(); i$.hasNext();) { ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer)i$.next(); //遍历消费者,消费消息 if(consumer.iterate()) return true; } MessageDispatch message = messageQueue.dequeueNoWait(); if(message == null) { return false; } else { //分发为消费的消息 dispatch(message); return !messageQueue.isEmpty(); } }
我们来看这部分
ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer)i$.next();
//遍历消费者,消费消息
if(consumer.iterate())
return true;
//ActiveMQMessageConsumer
public boolean iterate() { MessageListener listener = (MessageListener)messageListener.get(); if(listener != null) { //从未消费消息通道,获取未消费消息 MessageDispatch md = unconsumedMessages.dequeueNoWait(); if(md != null) { //如果有未消费的消息,则分发消息 dispatch(md); return true; } } return false; }
//分发消息
public void dispatch(MessageDispatch md) { ActiveMQMessage message = createActiveMQMessage(md); beforeMessageIsConsumed(md); try { boolean expired = isConsumerExpiryCheckEnabled() && message.isExpired(); if(!expired) //关键在这一句调用监听器的消费消息方法onMessage listener.onMessage(message); afterMessageIsConsumed(md, expired); } }
//从未消费消息通道,获取未消费消息
MessageDispatch md = unconsumedMessages.dequeueNoWait();
以先进先出消息通道为例FifoMessageDispatchChannel
//FifoMessageDispatchChannel
public class FifoMessageDispatchChannel implements MessageDispatchChannel { private final Object mutex = new Object(); private final LinkedList list = new LinkedList();//未分发消息队列 private boolean closed; private boolean running; public MessageDispatch dequeueNoWait() { Object obj = mutex; JVM INSTR monitorenter ; if(closed || !running || list.isEmpty()) return null; //从消息队列获取队列头消息 (MessageDispatch)list.removeFirst(); obj; JVM INSTR monitorexit ; return; Exception exception; exception; throw exception; } }
小节:
消费者启动主要是唤醒ActiveMQSessionExecutor,会话执行器唤醒主要做的做工作是
ActiveMQConnection创建任务执行TaskRunnerFactory,有任务执行工厂TaskRunnerFactory,有任务执行工厂创建执行任务PooledTaskRunner,PooledTaskRunner是ActiveMQSessionExecutor的包装,PooledTaskRunner执行就是执行ActiveMQSessionExecutor
iterate的函数,这个过程主要是ActiveMQSessionExecutor从ActiveMQSession获取会话消费者consumer,从未分发消息队列获取消息,然后遍历消费者,消费者通过MessageListener消费消息。
回到PooledTaskRunner
//唤醒会话执行器,执行PooledTaskRunner,分发未消费的消息给消费者
public void wakeup() throws InterruptedException { { synchronized(runable) { if(!queued && !shutdown) break label0; } return; } queued = true; //执行PooledTaskRunner if(!iterating) executor.execute(runable); }
下面来看消费者消费的两种方式
消费消息两种方式
第一种消费消息方式:
while (true) { //设置接收者接收消息的时间,为了便于测试,这里谁定为100s TextMessage message = (TextMessage) consumer.receive(100000); if (null != message) { System.out.println("收到消息" + message.getText()); } else { break; } }*/ }
public javax.jms.Message receive(long timeout) throws JMSException { checkClosed(); checkMessageListener(); if(timeout == 0L) return receive(); sendPullCommand(timeout); if(timeout > 0L) { MessageDispatch md; if(info.getPrefetchSize() == 0) md = dequeue(-1L); else //获取消息 md = dequeue(timeout); if(md == null) { return null; } else { beforeMessageIsConsumed(md); afterMessageIsConsumed(md, false); //包装消息 return createActiveMQMessage(md); } } else { return null; } }
//获取消息
md = dequeue(timeout);
private MessageDispatch dequeue(long timeout) throws JMSException { long deadline; deadline = 0L; if(timeout > 0L) deadline = System.currentTimeMillis() + timeout; //从未消费消息通道获取消息 MessageDispatch md = unconsumedMessages.dequeue(timeout); } //包装消息 return createActiveMQMessage(md); private ActiveMQMessage createActiveMQMessage(final MessageDispatch md) throws JMSException { //获取消息类型 ActiveMQMessage m = (ActiveMQMessage)md.getMessage().copy(); if(m.getDataStructureType() == 29) ((ActiveMQBlobMessage)m).setBlobDownloader(new BlobDownloader(session.getBlobTransferPolicy())); if(transformer != null) { //转换消息 javax.jms.Message transformedMessage = transformer.consumerTransform(session, this, m); if(transformedMessage != null) m = ActiveMQMessageTransformation.transformMessage(transformedMessage, session.connection); } if(session.isClientAcknowledge()) m.setAcknowledgeCallback(new Callback() { public void execute() throws Exception { session.checkClosed(); //如消息需要消费者回复,则产生回复消息 session.acknowledge(); } final ActiveMQMessageConsumer this$0; { this$0 = ActiveMQMessageConsumer.this; super(); } }); else if(session.isIndividualAcknowledge()) m.setAcknowledgeCallback(new Callback() { public void execute() throws Exception { session.checkClosed(); acknowledge(md); } final MessageDispatch val$md; final ActiveMQMessageConsumer this$0; { this$0 = ActiveMQMessageConsumer.this; md = messagedispatch; super(); } }); return m; }
从消费者直接消费消息来看,消费首先从未消费消息通道(FIFO,Priority)获取消息,然后转换消息。
第二种消费消息方式:
consumer.setMessageListener(new MessageListener(){//有事务限制 @Override public void onMessage(Message message) { try { ObjectMessage objMessage=(ObjectMessage)message; Order order = (Order)objMessage.getObject(); System.out.println("消费订单信息:"+order.toString()); } catch (JMSException e1) { e1.printStackTrace(); } try { session.commit(); } catch (JMSException e) { e.printStackTrace(); } } });
设置消息监听器
public void setMessageListener(MessageListener listener) throws JMSException { checkClosed(); if(info.getPrefetchSize() == 0) throw new JMSException("Illegal prefetch size of zero. This setting is not supported for asynchronous consumers please set a value of at least 1"); if(listener != null) { boolean wasRunning = session.isRunning(); if(wasRunning) session.stop(); //设置消费者消息监听器 messageListener.set(listener); //会话重新分发未消费消息 session.redispatch(this, unconsumedMessages); if(wasRunning) session.start(); } else { messageListener.set(null); } }
//会话重新分发未消费消息
session.redispatch(this, unconsumedMessages);
//ActiveMQSession
public void redispatch(ActiveMQDispatcher dispatcher, MessageDispatchChannel unconsumedMessages) throws JMSException { List c = unconsumedMessages.removeAll(); MessageDispatch md; for(Iterator i$ = c.iterator(); i$.hasNext(); connection.rollbackDuplicate(dispatcher, md.getMessage())) md = (MessageDispatch)i$.next(); Collections.reverse(c); MessageDispatch md; //遍历为未消费消息,会话执行器通知消息者消费消息 for(Iterator iter = c.iterator(); iter.hasNext(); executor.executeFirst(md)) md = (MessageDispatch)iter.next(); }
public class ActiveMQSessionExecutor void executeFirst(MessageDispatch message) { //将未消费消息放入消息队列,待消费者消费 messageQueue.enqueueFirst(message); //这个前面看到,唤醒消费者消费消息 wakeup(); }
监听器方式实际为会话从未消费消息队列获取消息,添加到消息队列,通过会话执行器通知消费者消费
总结:
创建消费者就是初始化消费者,传输延时,选择器,消息监听器,消息重传策略,并把消费者信息发送给broker,同时将消费者添加到会话中,启动会话执行器,通知消息者消费消息;消费者启动主要是唤醒ActiveMQSessionExecutor,会话执行器唤醒主要做的做工作是
ActiveMQConnection创建任务执行TaskRunnerFactory,有任务执行工厂TaskRunnerFactory,有任务执行工厂创建执行任务PooledTaskRunner,PooledTaskRunner是ActiveMQSessionExecutor的包装,PooledTaskRunner执行就是执行ActiveMQSessionExecutor
iterate的函数,这个过程主要是ActiveMQSessionExecutor从ActiveMQSession获取会话消费者consumer,从未分发消息队列获取消息,然后遍历消费者,消费者通过MessageListener消费消息。消费者直接消费消息方式为,消费首先从未消费消息通道(FIFO,Priority)获取消息,然后转换消息;监听器方式,实际为会话从未消费消息队列获取消息,添加到消息队列,通过会话执行器通知消费者消费。
public class MessageDispatch extends BaseCommand { public static final byte DATA_STRUCTURE_TYPE = 21; protected ConsumerId consumerId;//消费者id protected ActiveMQDestination destination;//消息目的地 protected Message message;//消息 protected int redeliveryCounter;//重传计数器 protected transient long deliverySequenceId; protected transient Object consumer;//消费者 protected transient TransmitCallback transmitCallback; protected transient Throwable rollbackCause; public MessageDispatch() { } public byte getDataStructureType() { return 21; } public boolean isMessageDispatch() { return true; } public ConsumerId getConsumerId() { return consumerId; } public void setConsumerId(ConsumerId consumerId) { this.consumerId = consumerId; } public ActiveMQDestination getDestination() { return destination; } public void setDestination(ActiveMQDestination destination) { this.destination = destination; } public Message getMessage() { return message; } public void setMessage(Message message) { this.message = message; } public long getDeliverySequenceId() { return deliverySequenceId; } public void setDeliverySequenceId(long deliverySequenceId) { this.deliverySequenceId = deliverySequenceId; } public int getRedeliveryCounter() { return redeliveryCounter; } public void setRedeliveryCounter(int deliveryCounter) { redeliveryCounter = deliveryCounter; } public Object getConsumer() { return consumer; } public void setConsumer(Object consumer) { this.consumer = consumer; } public Response visit(CommandVisitor visitor) throws Exception { return visitor.processMessageDispatch(this); } public TransmitCallback getTransmitCallback() { return transmitCallback; } public void setTransmitCallback(TransmitCallback transmitCallback) { this.transmitCallback = transmitCallback; } public Throwable getRollbackCause() { return rollbackCause; } public void setRollbackCause(Throwable rollbackCause) { this.rollbackCause = rollbackCause; } }
//消息获取策略
public class ActiveMQPrefetchPolicy implements Serializable { public static final int MAX_PREFETCH_SIZE = 32767; public static final int DEFAULT_QUEUE_PREFETCH = 1000; public static final int DEFAULT_QUEUE_BROWSER_PREFETCH = 500; public static final int DEFAULT_DURABLE_TOPIC_PREFETCH = 100; public static final int DEFAULT_OPTIMIZE_DURABLE_TOPIC_PREFETCH = 1000; public static final int DEFAULT_TOPIC_PREFETCH = 32767; private static final Logger LOG = LoggerFactory.getLogger(org/apache/activemq/ActiveMQPrefetchPolicy); private int queuePrefetch;//队列策略 private int queueBrowserPrefetch; private int topicPrefetch;//主题策略 private int durableTopicPrefetch; private int optimizeDurableTopicPrefetch; private int maximumPendingMessageLimit; public ActiveMQPrefetchPolicy() { queuePrefetch = 1000; queueBrowserPrefetch = 500; topicPrefetch = 32767; durableTopicPrefetch = 100; optimizeDurableTopicPrefetch = 1000; } }