Openfire階段實踐總結,Openfire實踐總結

來源:互聯網
上載者:User

Openfire階段實踐總結,Openfire實踐總結

從3月開始研究Openfire,其實就是要做一套IM系統,也正是這個原因才瞭解到Openfire。之前還真沒想過有這麼多的開源產品可以做IM,而且也沒想到XMPP這個協議竟然如何強大。看來還是標準為先,好的標準可以推動產業發展啊。

 

Openfire的搭建與簡單的demo之前寫過篇《技術筆記:XMPP之openfire+spark+smack》,當時主要關注的怎麼讓這套體系跑起來吧,只不過現在還是在這個階段,只是多學了點東西留下點筆記吧。

 

1、對於XMPP的學習很重要

最開始覺得搭建一套Openfire+spark太簡單啦,而且將spark的介面修改一下就可以變成一個新的產品,所以當時覺得XMPP協議這麼高深的東西不用太深入。只不過隨著簡單的事情結束了才發現,最核心的還是協議本身,瞭解協議可以更瞭解系統的運作,才能體會到這套系統是有多複雜。當然是對於我來說有點複雜,特別是涉及到前後端結合設計與開始時。

為此我推薦一個國內的XMPP協議翻譯網站:http://wiki.jabbercn.org/%E9%A6%96%E9%A1%B5。

當然如果英文好那就原版吧:http://xmpp.org/about/technology-overview.html

經過一段時間學習後,感覺QQ和在基礎原理上真的和XMPP很類似,只是使用的協議格式有些差別,或許這就是即時通訊的抽象層次吧。但是使用XML這種標記語言是不是很浪費流量呢?雖然XMPP擴充起來非常方便,但是就這些標籤也著實夠大的,像平常的文字交談時,或許中間標記產生的流量也和聊天內容相當了。畢竟我還沒到這種需要考慮大流量的階段,所以這隻是一個想法而已。

2、Openfire的一些設計點與思路

Openfire的原始碼整體看了看還是比較清晰的,擴充上支援外掛程式與組件模式。在最近擴充的中發現openfire的原始碼本身不太好去修改,依賴性很強,唯獨模組間的依賴比較鬆散些,模組內的類依賴基本是緊耦合的。只不過Openfire可以通過外掛程式擴充,對原始碼本身的依賴就小了許多,所以說整體來說還是很不錯的。

在Openfire中的外掛程式擴充方式主要是:

  • IQHandler

在XMPP協議中IQ包是指的資訊/查詢,可以用於伺服器與用戶端之間進行資料查詢,Openfir中實現了一個IQRouter來處理IQ包。自然IQHandler就是具體的IQ包處理單元啦。IQHandler是基於namespace來進行攔截處理的,自訂自己的命名空間後即可。

IQHandler提供了兩個抽象方法,用於衍生類別實現:

    /**     * Handles the received IQ packet.     *     * @param packet the IQ packet to handle.     * @return the response to send back.     * @throws UnauthorizedException if the user that sent the packet is not     *      authorized to request the given operation.     */    public abstract IQ handleIQ(IQ packet) throws UnauthorizedException;    /**     * Returns the handler information to help generically handle IQ packets.     * IQHandlers that aren't local server iq handlers (e.g. chatbots, transports, etc)     * return <tt>null</tt>.     *     * @return The IQHandlerInfo for this handler     */    public abstract IQHandlerInfo getInfo();

handleIQ方法就是解包和業務處理過程,最後返回結果包。

getInfo是用於返回當前IQHandler的命令空間

然後要使這個handler生效還需要註冊到IQRouter,可以在外掛程式啟動時建立IQHandler的對象並add進去:

@Override    public void initializePlugin(PluginManager manager, File pluginDirectory) {        iqHandler = new IQGroupChatHander();        iqRouter = XMPPServer.getInstance().getIQRouter();        iqRouter.addHandler(iqHandler);    }    @Override    public void destroyPlugin() {        iqRouter.removeHandler(iqHandler);    }

 

  • Compoent

Compoent也是一種比較常用的擴充方法,可以通過對特定子域的包進行處理。比如MUC通過註冊不同的Service,每個Service都有一個subdomain,系統會將不同的subdomain的資料包分發到專門服務中處理。這樣就帶來了一個好處,可以完全自訂一套子域的包處理業務,後面實現公眾號訂閱號就想通過這種思路來解決。而且Openfire還有遠程組件的機制,可以擴充成為一個獨立的業務系統,這樣openfire可以只充當訊息處理的核心。

具體的應用也比較簡單,實現Component介面,並註冊到ComponentManager中。而Component介面中最為重要的方法就是processPacket方法,代碼如下:

    /**     * Processes a packet sent to this Component.     *     * @param packet the packet.     * @see ComponentManager#sendPacket(Component, Packet)     */    public void processPacket(Packet packet);

注意方法中的參數是Packet,這個表示所有子域下的通訊原語都可以用於這裡處理。

註冊與退出的方法如下:

       componentManager = ComponentManagerFactory.getComponentManager();        try {            componentManager.addComponent("subdomain", this);        }        catch (Exception e) {            Log.error(e.getMessage(), e);            System.err.println(e);        }        try {            componentManager.removeComponent("subdomain");        } catch (ComponentException e) {            Log.error(e.getMessage(), e);        }
  • PacketInterceptor

在Openfire中所以的傳輸都是基於packet,在packet上再派生出不同的通訊原語,如message、roster、JID、IQ等等。基於這個原理只要提供一套對於包的攔截機制就可以實現一套比較強大的擴充機制。在Openfire中就提供了這樣的機制處理。在IQRouter\PresenceRouter\MessageRouter中都提供了對於包的攔截器。

// Invoke the interceptors before we process the read packet            InterceptorManager.getInstance().invokeInterceptors(packet, session, true, false);

攔截器都註冊在InterceptorManager中,在路由處理包時都會調用攔截器,上面的代碼就是在路由中截取的代碼例子。

那麼同樣的實現一個攔截器PacketInterceptor介面,並註冊到InterceptorManager即可。

InterceptorManager.getInstance().addInterceptor(interceptor);InterceptorManager.getInstance().removeInterceptor(interceptor);

 

有了以上三種方法,Openfire可以發展出各種用法,所以官方自己也實現了放多外掛程式供使用。在此也建議對於openfire的擴充最好還是使用外掛程式吧,除非自己的定製要求很高,Openfire本身已經不適應了的。

我的要求基本都可以達成,而且這樣以後升級新版本也非常簡單,不會出現問題。

3、Spark的糾結

Spark同樣出自於jivesoftware,但感覺擴充上就不那麼好了。也許是我沒有完全弄明白它的擴充原理吧。其實我的需求是重寫Spark的UI,同時加入自己的功能,比如群、訂閱號等。最開始想著Spark也是支援外掛程式的,但是最後改代碼時才發現,裡面依賴太深了,基本上和介面相關的都存在依賴,最後可能都要重寫一套。

其實在Spark中是有一個UIComponentRegistry類的,一些主要的介面都在這個類中註冊的。但可惡的是這些註冊的類大多都不能派生出新類來替換這些註冊的類。比如

private static Class<? extends ChatRoom> chatRoomClass = ChatRoomImpl.class;

這是聊天視窗的註冊類,那麼如果我想寫一個自己的聊天視窗,是不是直接把這個註冊類替換即可呢?不行,因為在其他代碼會盡然會這樣使用

    @Override    public void filesDropped(Collection<File> files, Component component) {    if (component instanceof ChatRoomImpl) {        ChatRoomImpl roomImpl = (ChatRoomImpl) component;        for (File file : files) {        SparkManager.getTransferManager().sendFile(file,            roomImpl.getParticipantJID());        }        SparkManager.getChatManager().getChatContainer()            .activateChatRoom(roomImpl);    }    }

在另一個類裡盡然直接使用衍生類別進行了類型判斷,這還只是一個點,類似的點太多了。所以最開始想著通過派生UIComponentRegistry中註冊的類來達到預期目的已經不大可能了。再加上時間有限,也就懶得管這麼多了,就讓開發直接在原始碼上改。

 

可惡的是2.7.7版本升級時發現代碼大變,這個版本升級smack4.x版本,而且大量使用了1.8的新特性。所以又經過了一番代碼合并才升級上來。另外說到smack基本不提供擴充,只提供事件的訂閱。

只不過spark是跨平台的,很容易就能在mac下運行,而且代碼是java的,暫時還不想拋棄掉,等將來考慮是不是再重寫吧。

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.