zoukankan      html  css  js  c++  java
  • (转)OpenFire源码学习之四:openfire的启动流程

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413233

    openfire启动

    ServerStarter

    启动流程图:

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

    [java] view plain copy
     
    1. Thread.currentThread().setContextClassLoader(loader);  
    2.             Class containerClass = loader.loadClass(  
    3.                     "org.jivesoftware.openfire.XMPPServer");  
    4.             containerClass.newInstance();  

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

    [java] view plain copy
     
    1. ClassLoader loader = new JiveClassLoader(parent, libDir);  

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

    Parent就是AppClassLoader加载器。

    XMPPServer

    ——核心启动类

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

    初始化

    ——初始化操作initialize()

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

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

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

    setup-datasource-standard.jsp

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

    以下为代码清单

    [java] view plain copy
     
    1. JiveGlobals.setXMLProperty("connectionProvider.className",  
    2.                     "org.jivesoftware.database.DefaultConnectionProvider");  
    3. DefaultConnectionProvider conProvider = new DefaultConnectionProvider();  
    4.      try {  
    5.             //设置驱动  
    6.             conProvider.setDriver(driver);  
    7.             //连接超时  
    8.             conProvider.setConnectionTimeout(connectionTimeout);  
    9.             //最小连接  
    10.             conProvider.setMinConnections(minConnections);  
    11.             conProvider.setMaxConnections(maxConnections);  
    12.             conProvider.setServerURL(serverURL);  
    13.             conProvider.setUsername(username);  
    14.             conProvider.setPassword(password);  
    15.         conProvider.setTestSQL(DbConnectionManager.getTestSQL(driver));  
    16.         //设置系统属性  
    17.             JiveGlobals.setXMLProperty("database.defaultProvider.driver", driver);  
    18.             JiveGlobals.setXMLProperty("database.defaultProvider.serverURL", serverURL);  
    19.             JiveGlobals.setXMLProperty("database.defaultProvider.username", username);  
    20.             JiveGlobals.setXMLProperty("database.defaultProvider.password", password);  
    21.         JiveGlobals.setXMLProperty("database.defaultProvider.testSQL",    
    22.                                 DbConnectionManager.getTestSQL(driver));  
    23.                             ......  

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

    [java] view plain copy
     
    1. DbConnectionManager.setConnectionProvider(conProvider);  

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

    加载插件模块

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

    [java] view plain copy
     
    1. pluginManager = new PluginManager(pluginDir);  

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

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

    1、数据库验证

    [java] view plain copy
     
    1. private void verifyDataSource() {  
    2.         Connection con = null;  
    3.         PreparedStatement pstmt = null;  
    4.         ResultSet rs = null;  
    5.         try {  
    6.             con = DbConnectionManager.getConnection();  
    7.             pstmt = con.prepareStatement("SELECT count(*) FROM ofID");  
    8.             rs = pstmt.executeQuery();  
    9.             rs.next();  
    10.         }  
    11.         catch (Exception e) {  
    12.             System.err.println("Database setup or configuration error: " +  
    13.                     "Please verify your database settings and check the " +  
    14.                     "logs/error.log file for detailed error messages.");  
    15.             Log.error("Database could not be accessed", e);  
    16.             throw new IllegalArgumentException(e);  
    17.         }  
    18.         finally {  
    19.             DbConnectionManager.closeConnection(rs, pstmt, con);  
    20.         }  
    21.     }  

    2、加载启动模块

    [java] view plain copy
     
    1. private void loadModules() {  
    2.        // 加载启动模块  
    3.        loadModule(RoutingTableImpl.class.getName());  
    4.        loadModule(AuditManagerImpl.class.getName());  
    5.        loadModule(RosterManager.class.getName());  
    6.        loadModule(PrivateStorage.class.getName());  
    7.        // 加载核心模块  
    8.        loadModule(PresenceManagerImpl.class.getName());  
    9.        loadModule(SessionManager.class.getName());  
    10.        loadModule(PacketRouterImpl.class.getName());  
    11.        loadModule(IQRouter.class.getName());  
    12.        loadModule(MessageRouter.class.getName());  
    13.        loadModule(PresenceRouter.class.getName());  
    14.        loadModule(MulticastRouter.class.getName());  
    15.        。。。。。。  
    16.        // 加载标准handler载模块  
    17.        loadModule(IQBindHandler.class.getName());  
    18.        loadModule(IQSessionEstablishmentHandler.class.getName());  
    19.        loadModule(IQAuthHandler.class.getName());  
    20.        loadModule(IQPingHandler.class.getName());  
    21.        loadModule(IQPrivateHandler.class.getName());  
    22.        loadModule(IQRegisterHandler.class.getName());  
    23.        。。。。。。  
    24.        // 连接管理  
    25.        loadModule(ConnectionManagerImpl.class.getName());  
    26.        // Keep a reference to the internal component manager  
    27.        componentManager = getComponentManager();  
    28.    }  

    3.初始化模块

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

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

    [java] view plain copy
     
    1. private void initModules() {  
    2.         for (Module module : modules.values()) {  
    3.             boolean isInitialized = false;  
    4.             try {  
    5.                 module.initialize(this);  
    6.                 isInitialized = true;  
    7.             }  
    8.             catch (Exception e) {  
    9.                 e.printStackTrace();  
    10.                 // Remove the failed initialized module  
    11.                 this.modules.remove(module.getClass());  
    12.                 if (isInitialized) {  
    13.                     module.stop();  
    14.                     module.destroy();  
    15.                 }  
    16.                 Log.error(LocaleUtils.getLocalizedString("admin.error"), e);  
    17.             }  
    18.         }  
    19.     }  

    4.启动插件模块

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

    [java] view plain copy
     
    1. private void startModules() {  
    2.         for (Module module : modules.values()) {  
    3.             boolean started = false;  
    4.             try {  
    5.                 module.start();  
    6.             }  
    7.             catch (Exception e) {  
    8.                 if (started && module != null) {  
    9.                     module.stop();  
    10.                     module.destroy();  
    11.                 }  
    12.                 Log.error(LocaleUtils.getLocalizedString("admin.error"), e);  
    13.             }  
    14.         }  
    15.     }  

    启动插件监控管理

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

    [java] view plain copy
     
    1. public void start() {  
    2.         executor = new ScheduledThreadPoolExecutor(1);  
    3.         // See if we're in development mode. If so, check for new plugins once every 5 seconds.  
    4.         // Otherwise, default to every 20 seconds.  
    5.         if (Boolean.getBoolean("developmentMode")) {  
    6.             executor.scheduleWithFixedDelay(pluginMonitor, 0, 5, TimeUnit.SECONDS);  
    7.         }  
    8.         else {  
    9.             executor.scheduleWithFixedDelay(pluginMonitor, 0, 20, TimeUnit.SECONDS);  
    10.         }  
    11.     }  

    通知监听

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

    [java] view plain copy
     
    1. for (XMPPServerListener listener : listeners) {  
    2.                 listener.serverStarted();  
    3.             }  

    这个通知消息说明服务器所有模块已经启动完成。这个时候就是监听消息的发送和接收了。但也有可能有些插件也会等待被装载。

  • 相关阅读:
    SpringBoot java.lang.IllegalArgumentException: Request header is too large
    (转)以太坊 钱包 创建 导入 Keystore
    (转)以太坊数据同步常见问题集锦
    以太坊nonce
    (转)Fabric 1.0 读写集
    (转)Fabric CA环境的集成
    Hyperledger Fabric CA的命令行用法
    oracle新建表空间与用户
    积分智能合约
    远程桌面,身份验证错误:要求的函数不正确等解决办法
  • 原文地址:https://www.cnblogs.com/wangle1001986/p/7151821.html
Copyright © 2011-2022 走看看