增加一个消息消费者
在transportConnection中注册了一个消息监听器DefaultTransportListener 当客户端有动作的的时候,通过消息监听器的oncommand进行处理。
当有一个消费者进入,则调用该类中的processAddConsumer 方法。具体调用流程如下:
消息到达服务器端之后,会被Subscription的add方法处理。主要内容是判断消息所属的destination是否存在,如果不存在,则直接返回。存在则将消息添加到PendingMessageCursor中。PendingMessageCursor是用于处理给消费者发送的消息的游标。也就相当于缓存要发给消费者的消息。
Subscription 接口:通过接口定义的行为,我们可以看出,主要是和消息的发布的行为相关。比如ad(messageReference) 是增加一个消息,add(ConnectionContext context, Destination destination)则是增加一个一个订阅的消息终端。
每一个订阅对应一个客户端,在每一个订阅对象中,存在一个主题list。那么该订阅就能记录所有的该用户订阅的主题。当增加一个订阅的时候,执行如下方法:
destinations.add(destination);// AbstractSubscription
pending.add(context,destination);// PrefetchSubscription
对应的实现类PrefetchSubscription中存在一个PendingMessageCursor 属性,他是一个将消息发送给客户端的游标。
那么,一个游标怎么能够处理所有的订阅主题呢??
我们以topic处理对应的游标StoreDurableSubscriberCursor 来分析。我们来看游标中这两个属性:
所以,当添加一个消费者订阅的时候,在执行pending.add(context,destination);// PrefetchSubscription这个方法的时候,也就是执行了StoreDurableSubscriberCursor中的add方法:
@Override
public synchronized voidadd(ConnectionContext context, Destination destination) throws Exception {
if (destination != null && !AdvisorySupport.isAdvisoryTopic(destination.getActiveMQDestination())){
TopicStorePrefetch tsp= new TopicStorePrefetch(this.subscription,(Topic)destination, clientId, subscriberName);
tsp.setMaxBatchSize(destination.getMaxPageSize());
tsp.setSystemUsage(systemUsage);
tsp.setMessageAudit(getMessageAudit());
tsp.setEnableAudit(isEnableAudit());
tsp.setMemoryUsageHighWaterMark(getMemoryUsageHighWaterMark());
tsp.setUseCache(isUseCache());
tsp.setCacheEnabled(isUseCache()&& tsp.isEmpty());
topics.put(destination, tsp);
storePrefetches.add(tsp);
if (isStarted()) {
tsp.start();
}
}
}
在该方法中构建一个TopicStorePrefetch 对象,并添加到订阅的list中。所以,cursor就有了通过一个游标管理所有主题消息分发的能力。
上面只是添加一个消费者的流程,他和订阅以及生产者都不是一条线。
同构建一个消费者一样,构建一个生产者也是这个流程。
发送消息
org.apache.activemq.broker.region.policy.SimpleDispatchPolicy
发送消息的处理流程基本如下:
前面的两步相对比较简单,看topic的send方法。
在topic持有一个list属性用来存储该topic下的所有的订阅
所以呢在发消息的时候,直接向改topic下所有的订阅者发送就可以啦
向一个订阅发送消息
向一个订阅发送消息,也就是通过Subscription 中的add(MessageReference node) 方法进行发送。
其实这个方法核心代码也就两行:
pending.addMessageLast(node);
dispatchPending();
先看pending中的addMessagelast
这个方法中,如果消息是不需要持久化的,则直接添加到了 nonPersistent中。如果需要持久化,则添加到了TopicStorePrefetch 中。
注意,这里的nonPersistent 是根据brokerService中的persistent配置来生成的,如果该属性为true,则生成一个FilePendingMessageCursor,否则生成一个VMPendingMessageCursor。他们都是临时存储消息的。只不过一个是通过文件存储,一个是通过jvm存储的。