您的位置:首页 > 运维架构

(转)OpenFire源码学习之四:openfire的启动流程

2017-07-11 17:47 471 查看
转:http://blog.csdn.net/huwenfeng_2011/article/details/43413233

openfire启动

ServerStarter

启动流程图:



启动的总入口在ServerStarter的main方法中。通过上图首先它会先加载它所需要的jar文件。最后通过Java反射机制将XMPPServer加入当前线程。

[java] view plain copy

Thread.currentThread().setContextClassLoader(loader);

Class containerClass = loader.loadClass(

"org.jivesoftware.openfire.XMPPServer");

containerClass.newInstance();

当它获取当前执行的线程对象Thread.currentThread()然后设置为这个线程上下文类加载器,将loader加载进去。而loader是什么呢?再向上看它的源码:

[java] view plain copy

ClassLoader loader = new JiveClassLoader(parent, libDir);

libDir就没什么好说的了。Parent就是:ClassLoader parent = Thread.currentThread().getContextClassLoader();

Parent就是AppClassLoader加载器。

XMPPServer

——核心启动类

XmppServer中的启动顺序机制,如图:



初始化

——初始化操作initialize()



initialize方法执行的时候会根据配置文件的<setup>节点属性值来判断系统是否第一次启动在openfire_src\target\openfire\conf目录下的openfire.xml文件中也配置着系统的基本信息。这些基本的信息包括:DB连接供应商,数据库连接的基本信息,端口,语言环境等。

如果<setup>节点值默认为false。那么在第一次打开系统的时候会出现系统配置信息的界面。如图所示:



在这里的每次设置都会把值传递给connectionManager连接管理对象。继续下一部也就是到安装数据库信息配置的时候会跳转到这个页面:

setup-datasource-standard.jsp



在这里OpenFire会把数据库配置信息写入到openfire.xml配置文件当中。

以下为代码清单

[java] view plain copy

JiveGlobals.setXMLProperty("connectionProvider.className",

"org.jivesoftware.database.DefaultConnectionProvider");

DefaultConnectionProvider conProvider = new DefaultConnectionProvider();

try {

//设置驱动

conProvider.setDriver(driver);

//连接超时

conProvider.setConnectionTimeout(connectionTimeout);

//最小连接

conProvider.setMinConnections(minConnections);

conProvider.setMaxConnections(maxConnections);

conProvider.setServerURL(serverURL);

conProvider.setUsername(username);

conProvider.setPassword(password);

conProvider.setTestSQL(DbConnectionManager.getTestSQL(driver));

//设置系统属性

JiveGlobals.setXMLProperty("database.defaultProvider.driver", driver);

JiveGlobals.setXMLProperty("database.defaultProvider.serverURL", serverURL);

JiveGlobals.setXMLProperty("database.defaultProvider.username", username);

JiveGlobals.setXMLProperty("database.defaultProvider.password", password);

JiveGlobals.setXMLProperty("database.defaultProvider.testSQL",

DbConnectionManager.getTestSQL(driver));

......

读写openfire文件属性之后,系统会测试数据库连接并生成数据表结构。通过一下方法完成操作

[java] view plain copy

DbConnectionManager.setConnectionProvider(conProvider);

然后检查数据库是否要更新

加载插件模块

of中所有的插件都以jar或war文件存在

[java] view plain copy

pluginManager = new PluginManager(pluginDir);

XMPPServer中 插件管理器(PluginManager)会添加插件的基本信息如:插件的实体、插件所在的目录、插件文件、插件监控等等

启动插件模块分为分为以下几个步骤:

1、数据库验证

[java] view plain copy

private void verifyDataSource() {

Connection con = null;

PreparedStatement pstmt = null;

ResultSet rs = null;

try {

con = DbConnectionManager.getConnection();

pstmt = con.prepareStatement("SELECT count(*) FROM ofID");

rs = pstmt.executeQuery();

rs.next();

}

catch (Exception e) {

System.err.println("Database setup or configuration error: " +

"Please verify your database settings and check the " +

"logs/error.log file for detailed error messages.");

Log.error("Database could not be accessed", e);

throw new IllegalArgumentException(e);

}

finally {

DbConnectionManager.closeConnection(rs, pstmt, con);

}

}

2、加载启动模块

[java] view plain copy

private void loadModules() {

// 加载启动模块

loadModule(RoutingTableImpl.class.getName());

loadModule(AuditManagerImpl.class.getName());

loadModule(RosterManager.class.getName());

loadModule(PrivateStorage.class.getName());

// 加载核心模块

loadModule(PresenceManagerImpl.class.getName());

loadModule(SessionManager.class.getName());

loadModule(PacketRouterImpl.class.getName());

loadModule(IQRouter.class.getName());

loadModule(MessageRouter.class.getName());

loadModule(PresenceRouter.class.getName());

loadModule(MulticastRouter.class.getName());

。。。。。。

// 加载标准handler载模块

loadModule(IQBindHandler.class.getName());

loadModule(IQSessionEstablishmentHandler.class.getName());

loadModule(IQAuthHandler.class.getName());

loadModule(IQPingHandler.class.getName());

loadModule(IQPrivateHandler.class.getName());

loadModule(IQRegisterHandler.class.getName());

。。。。。。

// 连接管理

loadModule(ConnectionManagerImpl.class.getName());

// Keep a reference to the internal component manager

componentManager = getComponentManager();

}

3.初始化模块

of中的所有插件都继承BasicModule,并实现initialize()方法

统一初始化所有的插件代码清代:

[java] view plain copy

private void initModules() {

for (Module module : modules.values()) {

boolean isInitialized = false;

try {

module.initialize(this);

isInitialized = true;

}

catch (Exception e) {

e.printStackTrace();

// Remove the failed initialized module

this.modules.remove(module.getClass());

if (isInitialized) {

module.stop();

module.destroy();

}

Log.error(LocaleUtils.getLocalizedString("admin.error"), e);

}

}

}

4.启动插件模块

of加载和初始化后的所有模块后的调用startModules()这个方法来遍历已知的模块和启动它们。

[java] view plain copy

private void startModules() {

for (Module module : modules.values()) {

boolean started = false;

try {

module.start();

}

catch (Exception e) {

if (started && module != null) {

module.stop();

module.destroy();

}

Log.error(LocaleUtils.getLocalizedString("admin.error"), e);

}

}

}

启动插件监控管理

插件监控管理——PluginMonitor。这个监控器会定时检查插件目录是否有新的插件添加。

[java] view plain copy

public void start() {

executor = new ScheduledThreadPoolExecutor(1);

// See if we're in development mode. If so, check for new plugins once every 5 seconds.

// Otherwise, default to every 20 seconds.

if (Boolean.getBoolean("developmentMode")) {

executor.scheduleWithFixedDelay(pluginMonitor, 0, 5, TimeUnit.SECONDS);

}

else {

executor.scheduleWithFixedDelay(pluginMonitor, 0, 20, TimeUnit.SECONDS);

}

}

通知监听

当of完成所有插件的初始化和启动后会通知监听器:XMPPServerListener。

[java] view plain copy

for (XMPPServerListener listener : listeners) {

listener.serverStarted();

}

这个通知消息说明服务器所有模块已经启动完成。这个时候就是监听消息的发送和接收了。但也有可能有些插件也会等待被装载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: