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的,暂时还不想抛弃掉,等将来考虑是不是再重写吧。

时间: 2024-10-10 17:24:24

Openfire阶段总结的相关文章

openfire的组件(Component)开发

在之前的文章<Openfire阶段实践总结>中提到过一种openfire的扩展模式Compoent.本文将主要探讨对这种模式的应用与开发方法. 内部与外部组件介绍 在openfire中的许多插件都实现了Compoent,Compoent的灵活性在于它可以通过对特定的二级子域包进行处理.在XMPP协议中最为明显的使用场景就是群聊,这就是一个典型的例子.看看openfire中的聊天室JID都是什么格式:[email protected],很明这里多了一个conference.对比用户的JID:[e

博客笔记索引

java开发相关 Tomcat shutdown执行后无法退出进程问题排查及解决 记一次tomcat线程创建异常调优:unable to create new native thread VisualVM通过jstatd方式远程监控远程主机 学习AOP之透过Spring的Ioc理解Advisor 学习AOP之深入一点Spring Aop 学习AOP之认识一下Spring AOP 加深一下BlockingQueue的认识 测试一下StringBuffer和StringBuilder及字面常量拼接三

移动应用和游戏开发两个阶段在线视频培训的未来计划

在51CTO学院开线上视频课程已经3个多月了,也上了不少课.不过发现还有很多课没有开.现在就将未来的开课计划公布一下.计划分为两个阶段.第一阶段主要是Cocos2d-x和Cocos2d-js的游戏开发培训.涉及到了<征服C++ 11>.<从零开始掌握Cocos2d-x 3.x>(共12季).<Cocos2d-x 3.x项目实战:仿微信飞机大战>.<Cocos2d-x 3.x项目实战:星空大战>,这是目前已经发布的4个课程,正在逐步更新中... 未来还会发布&

Openfire分析之二:主干程序分析

引言 宇宙大爆炸,于是开始了万物生衍,从一个连人渣都还没有的时代,一步步进化到如今的花花世界. 然而沧海桑田,一百多亿年过去了-. 好复杂,但程序就简单多了,main()函数运行,敲个回车,一行Hello World就出来了,所以没事多敲敲回车,可以练手感-. 一.程序入口 Java的程序入口是main方法,Openfire也不例外.可以全局检索一下"void main",可以看到,Openfire的main函数有两个: (1)org.jivesoftware.openfire.lau

UML和模式应用5:细化阶段(5)---系统顺序图

1.前言 系统顺序图(SSD)是为阐述系统相关的输入和输出事件而快速.简单的创建的制品,它们是操作契约和对象设计的输入. SSD展示了直接与系统交互的外部参与者.系统(作为黑盒)以及由参与者发起的系统事件. 应为每个用例的主成功场景,以及频繁发生的或者复杂的替代场景绘制SSD. 2.系统顺序图对其它制品的影响 图 系统顺序图对其它UP制品的影响 3. 为何绘制SSD? 因为需要准确的知道什么是外部输入的事件,这些事件时系统行为分析的重要部分 软件系统要为如下三种事件响应: 来自参与者(人或计算机

Python框架之Tornado(二)请求阶段

概述 上图是tornado程序启动以及接收到客户端请求后的整个过程,对于整个过程可以分为两大部分: 启动程序阶段,又称为待请求阶段(上图1.2所有系列和3.0) 接收并处理客户端请求阶段(上图3系列) 简而言之: 1.在启动程序阶段,第一步,获取配置文件然后生成url映射(即:一个url对应一个XXRequestHandler,从而让XXRequestHandler来处理指定url发送的请求):第二步,创建服务器socket对象并添加到epoll中:第三步,创建无线循环去监听epoll. 2.在

.Net学习路线以及各阶段学习书籍,博文,视频的分享

这份文档是我受一位Java大神的委托给15级想学.NET的师弟师妹写的.我想,博客园是我成长进步的地方,作为一个具有互联网分zhuang享bi精神的文艺女青年,我应该把它分享到这里来给更多需要想学.NET的童鞋让他们去成长,让他们少走学习上的一些弯路,写的不合理的地方,欢迎大家批评指正,或者有更好的学习方面的建议和学习资料,欢迎大家留言分享. 前言 各位师弟师妹们,大家好,我是信息13-2班的赖英凤.上星期,你们的班助财哥委托我整理C#的学习路线,还有一些学习资料,视频给大家,我想,作为一名即将

各项目意见(第一阶段)

团队名称 团队意见 1 理财猫 1 界面不是很美观,后期希望优化 2 希望可以和数据库相连 3 功能实现的还不是太完善,不过时钟还是不错的 2 跑什么操 1 主题不是很明显,希望可以和学校的日常出操联系起来 2 希望添加登录注册功能,望采纳 3 界面不是太美观,色调单一 3 水骑士 1 登录注册没有实现 2 功能实现太少,希望在下一阶段再接再厉 3 建议有两个客户端,一个买家版一个卖家版 4  铁大云盘 1 登录注册功能实现不完善,希望和学生学号联系起来,QQ连接想法不错希望后期实现 2 上传的

Java程序猿学习当中各个阶段的建议

回答阿里社招面试如何准备,顺便谈谈对于Java程序猿学习当中各个阶段的建议 引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容基本上忘得一干二净,所以写这篇文章其实是很有难度的. 但是,最近问LZ的人实在是太多了,为了避免重复回答,给自己省点力气,干脆就在这里统一回复了. 其实之前LZ写过一篇文章,但是那篇文章更多的是在讨论“面试前该不该刷题”这个