ActiceMQ實現mqtt協議的消息選擇器功能

如果要在amq上使用mqtt協議,有一個很大的問題是mqtt協議無法使用amq的消息選擇器功能,這樣就會造成一個很麻煩的情況:

  • 如果要用mqtt協議點對點發送消息,那么就需要為每個mqtt連接單獨建立一個queue或者topic,可amq對大量destination的支持并不好,測試中發現無法支撐超過9000個queue。也就是說如果要用amq實現mqtt連接的點對點發送,連接數就不能超過9000個。

在網上找了一圈,只有一篇類似的解決方法,是大神kimmking寫的:
使用ActiveMQ+MQTT實現Android點對點消息通知

但是這個方法太過麻煩,而且隨著mq版本升級,需要每次都改一下broker的代碼。

趁著今晚有空,根據之前的思路研究了一下這個問題的解決辦法。

消息選擇器的功能有兩個要素:

  • 消息生產者在消息屬性里帶上篩選的字段
  • 消費者在建立消費者的時候,注明消息選擇器

難點是mqtt協議既不支持消息屬性,也不支持帶上選擇器建立消費者。

我的項目里由于發送方可以不用mqtt協議,所以我主要考慮解決第二個難點,其實第一個難點的解決方法也類似,也可以通過插件實現。

第二個難點的解決方法是通過編寫插件,在broker執行addConsumer的時候,為每一個consumer自動加上一個ClientID='客戶端clientID'這樣的消息選擇器。插件的編寫方法見我上一篇文章
ActiveMQ插件開發

代碼如下:

package com.icbc.amqs;
import org.apache.activemq.broker.Broker;   
import org.apache.activemq.broker.BrokerPlugin;   
import org.apache.activemq.plugin.StatisticsBrokerPlugin;
import org.apache.commons.logging.Log;   
import org.apache.commons.logging.LogFactory;  

public class MqttSelectorPlugin implements BrokerPlugin {   

private Log log = LogFactory.getLog(StatisticsBrokerPlugin.class);  

public Broker installPlugin(Broker broker) throws Exception {   
log.info("install MqttSelectorPlugin ");   
return new MqttSelector(broker);   
}   
}  
package com.icbc.amqs;
import org.apache.activemq.broker.Broker;   
import org.apache.activemq.broker.BrokerFilter;   
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.broker.region.Subscription;
import org.apache.activemq.command.ConsumerInfo;
import org.apache.activemq.plugin.StatisticsBrokerPlugin;
import org.apache.commons.logging.Log;   
import org.apache.commons.logging.LogFactory;  

public class MqttSelector extends BrokerFilter{
private Log log;  

public MqttSelector(Broker next) {   
super(next);   
log = LogFactory.getLog(StatisticsBrokerPlugin.class); 
log.info("initialize Message Log plugin");
}  
    
//需要注意的是mqtt協議建立消費者的時候。consumerInfo里不會帶上clientID,只能從ConnectionContext中取。
    @Override
    public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception {
    if (info.getDestination().toString().contains("test")){
    info.setSelector("ClientID='"+context.getClientId()+"'");
    log.info("[Consumer] Adding consumer : "+ info);
    }     
        return super.addConsumer(context, info);
    }

}  

經測試,可以讓mqtt協議的消費者正常接收消息。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容