openfire啟動(dòng)
ServerStarter
啟動(dòng)流程圖:
啟動(dòng)的總入口在ServerStarter的main方法中。通過(guò)上圖首先它會(huì )先加載它所需要的jar文件。最后通過(guò)java反射機制將XMPPServer加入當前線(xiàn)程。
- Thread.currentThread().setContextClassLoader(loader);
- Class containerClass = loader.loadClass(
- "org.jivesoftware.openfire.XMPPServer");
- containerClass.newInstance();
當它獲取當前執行的線(xiàn)程對象Thread.currentThread()然后設置為這個(gè)線(xiàn)程上下文類(lèi)加載器,將loader加載進(jìn)去。而loader是什么呢?再向上看它的源碼:
- ClassLoader loader = new JiveClassLoader(parent, libDir);
libDir就沒(méi)什么好說(shuō)的了。Parent就是:ClassLoader parent = Thread.currentThread().getContextClassLoader();
Parent就是AppClassLoader加載器。
XMPPServer
——核心啟動(dòng)類(lèi)
XmppServer中的啟動(dòng)順序機制,如圖:
初始化
——初始化操作initialize()
initialize方法執行的時(shí)候會(huì )根據配置文件的<setup>節點(diǎn)屬性值來(lái)判斷系統是否第一次啟動(dòng)在openfire_src\target\openfire\conf目錄下的openfire.xml文件中也配置著(zhù)系統的基本信息。這些基本的信息包括:DB連接供應商,數據庫連接的基本信息,端口,語(yǔ)言環(huán)境等。
如果<setup>節點(diǎn)值默認為false。那么在第一次打開(kāi)系統的時(shí)候會(huì )出現系統配置信息的界面。如圖所示:
在這里的每次設置都會(huì )把值傳遞給connectionManager連接管理對象。繼續下一部也就是到安裝數據庫信息配置的時(shí)候會(huì )跳轉到這個(gè)頁(yè)面:
setup-datasource-standard.jsp
在這里OpenFire會(huì )把數據庫配置信息寫(xiě)入到openfire.xml配置文件當中。
以下為代碼清單
- JiveGlobals.setXMLProperty("connectionProvider.className",
- "org.jivesoftware.database.DefaultConnectionProvider");
- DefaultConnectionProvider conProvider = new DefaultConnectionProvider();
- try {
- //設置驅動(dòng)
- conProvider.setDriver(driver);
- //連接超時(shí)
- 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));
- ......
讀寫(xiě)openfire文件屬性之后,系統會(huì )測試數據庫連接并生成數據表結構。通過(guò)一下方法完成操作
- DbConnectionManager.setConnectionProvider(conProvider);
然后檢查數據庫是否要更新
加載插件模塊
of中所有的插件都以jar或war文件存在
- pluginManager = new PluginManager(pluginDir);
XMPPServer中 插件管理器(PluginManager)會(huì )添加插件的基本信息如:插件的實(shí)體、插件所在的目錄、插件文件、插件監控等等
啟動(dòng)插件模塊分為分為以下幾個(gè)步驟:
1、數據庫驗證
- 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、加載啟動(dòng)模塊- private void loadModules() {
- // 加載啟動(dòng)模塊
- 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,并實(shí)現initialize()方法
統一初始化所有的插件代碼清代:
- 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.啟動(dòng)插件模塊
of加載和初始化后的所有模塊后的調用startModules()這個(gè)方法來(lái)遍歷已知的模塊和啟動(dòng)它們。
- 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);
- }
- }
- }
啟動(dòng)插件監控管理
插件監控管理——PluginMonitor。這個(gè)監控器會(huì )定時(shí)檢查插件目錄是否有新的插件添加。
- 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);
- }
- }
通知監聽(tīng)
當of完成所有插件的初始化和啟動(dòng)后會(huì )通知監聽(tīng)器:XMPPServerListener。
- for (XMPPServerListener listener : listeners) {
- listener.serverStarted();
- }
這個(gè)通知消息說(shuō)明服務(wù)器所有模塊已經(jīng)啟動(dòng)完成。這個(gè)時(shí)候就是監聽(tīng)消息的發(fā)送和接收了。但也有可能有些插件也會(huì )等待被裝載。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。