Openfire的启动过程非常的简单,通过一个入口初始化lib目录下的openfire.jar包,并启动一个XMPPServer实例。
下面就是ServerStarter.start方法的代码片断:
Class containerClass = loader.loadClass("org.jivesoftware.openfire.XMPPServer"); containerClass.newInstance();
这样一个openfire实例就已经启动了。
XMPPServer类
这个XmppServer类是单实例的对象,这样在服务器调用时可以获取一个实例。既然是个对象就会有构造的过程,XMPPServer在构造过程中会对服务进行初始化,这个过程包括:
初始化配置参数
检查是否需要安装
初始化Module
启动统计模块
启动plugin
基本就是这么简单,还是非常简洁明了。这里也可以大概知道在openfire里主要是module和plugin两类模块,一般情况下内部的模块都用module,对于一些功能的扩展或者第三方的开发扩展使用Plugin。官方其实也会自己写一个插件来扩展功能,说明插件还是比较灵活的。
提一提Module的加载过程
下面代码是module的加载过程
if (!setupMode) { verifyDataSource(); // First load all the modules so that modules may access other modules while // being initialized loadModules(); // Initize all the modules initModules(); // Start all the modules startModules(); }
可以看到,分了三个步骤:
加载模块:是对模块类的实例化过程,就是创建对象
初始化模块:就是调用module.initialize(this);,其实就是调用模块的初始化方法
启动模块:module.start();,同理就是调用启动模块
这是因为openfire规范了module的接口抽象Module,所有的模块都要按照这个规范实现,看代码:
public interface Module { /** * Returns the name of the module for display in administration interfaces. * * @return The name of the module. */ String getName(); /** * Initialize the module with the container. * Modules may be initialized and never started, so modules * should be prepared for a call to destroy() to follow initialize(). * * @param server the server hosting this module. */ void initialize(XMPPServer server); /** * Start the module (must return quickly). Any long running * operations should spawn a thread and allow the method to return * immediately. */ void start(); /** * Stop the module. The module should attempt to free up threads * and prepare for either another call to initialize (reconfigure the module) * or for destruction. */ void stop(); /** * Module should free all resources and prepare for deallocation. */ void destroy(); }
这也标示了Module的生命周期,Openfire会管理这些Module的生命周期,以此来保证各个模块的启动与释放。
Connection管理模块
整个启动过程有点奇怪,并没有看到Openfire是如何监听端口的,如果不监听如何获利客户端连接呢?因为Openfire只通过Module来管理的,那么对应的网络管理应该就在Module中。于是在XMPPServer.loadModules方法中看到下面的代码:
// Load this module always last since we don't want to start listening for clients // before the rest of the modules have been started loadModule(ConnectionManagerImpl.class.getName());
ConnectionManagerImpl就是连接的管理模块,这里有个注释,就是在其他模块启动后之后再启动监听模块。
在ConnectionManagerImpl中管理了主要的连接,都是以ConnectionListener的来管理,这个类用于包装连接。我的理解就是一个连接抽象吧,这样对于代码来说写起来比较统一。看下面代码中Manager管理着哪些:
private final ConnectionListener clientListener; private final ConnectionListener clientSslListener; private final ConnectionListener boshListener; private final ConnectionListener boshSslListener; private final ConnectionListener serverListener; private final ConnectionListener componentListener; private final ConnectionListener componentSslListener; private final ConnectionListener connectionManagerListener; // Also known as 'multiplexer' private final ConnectionListener connectionManagerSslListener; // Also known as 'multiplexer' private final ConnectionListener webAdminListener; private final ConnectionListener webAdminSslListener;
这里面除了server只有一个外,其他的都是两个,其中一个是SSL的。它们主要是什么链接?
client:表示客户端连接
bosh:就是HTTP绑定的连接
server:服务器到服务器的socket连接
component:组件到服务器的连接
connectionManager:是指通过connectionManager连接器过来的连接
webAdmin:是指web控制台的连接
这里面bosh和webAdmin使用的是http协议,所以连接并不是长连接,其他的都是socket。
openfire里使用了Mina来实现socket网络处理。只不过看代码中对于S2S类型的连接使用的不是mina,如下代码: