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

openfire启动

ServerStarter

启动流程图:

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

  1. Thread.currentThread().setContextClassLoader(loader);
  2. Class containerClass = loader.loadClass(
  3. "org.jivesoftware.openfire.XMPPServer");
  4. containerClass.newInstance();

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

  1. 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配置文件当中。

以下为代码清单

  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文件属性之后,系统会测试数据库连接并生成数据表结构。通过一下方法完成操作

  1. DbConnectionManager.setConnectionProvider(conProvider);

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

加载插件模块

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

  1. pluginManager = new PluginManager(pluginDir);

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

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

1、数据库验证

  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、加载启动模块

  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()方法

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

  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()这个方法来遍历已知的模块和启动它们。

  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。这个监控器会定时检查插件目录是否有新的插件添加。

  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。

  1. for (XMPPServerListener listener : listeners) {
  2. listener.serverStarted();
  3. }

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

(转)OpenFire源码学习之四:openfire的启动流程的更多相关文章

  1. Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Job Manager 启动

    Job Manager 启动 https://t.zsxq.com/AurR3rN 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...

  2. Flink 源码解析 —— Standalone session 模式启动流程

    Standalone session 模式启动流程 https://t.zsxq.com/EemAEIi 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0 ...

  3. Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Task Manager 启动

    Task Manager 启动 https://t.zsxq.com/qjEUFau 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Ma ...

  4. Caddy源码阅读(二)启动流程与 Event 事件通知

    Caddy源码阅读(二)启动流程与 Event 事件通知 Preface Caddy 是 Go 语言构建的轻量配置化服务器.https://github.com/caddyserver/caddy C ...

  5. Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍

    最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...

  6. mybatis源码学习:插件定义+执行流程责任链

    目录 一.自定义插件流程 二.测试插件 三.源码分析 1.inteceptor在Configuration中的注册 2.基于责任链的设计模式 3.基于动态代理的plugin 4.拦截方法的interc ...

  7. (转)OpenFire源码学习之七:组(用户群)与花名册(用户好友)

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413651 Group 在openfire中的gorop——组,也可以理解为共享组.什 ...

  8. (转)OpenFire源码学习之二十七:Smack源码解析

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43484199 Smack Smack是一个用于和XMPP服务器通信的类库,由此可以实现即 ...

  9. (转)OpenFire源码学习之十八:IOS离线推送

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43458213 IOS离线推送 场景: 如果您有iOS端的APP,在会话聊天的时候,用户登 ...

随机推荐

  1. CDN技术之--该技术概述

    CDN关键技术:1. 缓存算法[Squid]:2. 分发能力:3. 负载均衡[Nginx](4. 基于DNS[BIND]):5. 支持协议: 缓存算法决定命中率.源服务器压力.POP节点存储能力分发能 ...

  2. 20175223 MySQL

    目录 完成结果 要求 1 :导入world.sql 要求 2 :CityWanna.java CityWanna.java 要求 3 :CountryWanna.java CountryWanna.j ...

  3. 线程同步(基于java)

    java线程 同步与异步 线程池 1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成 ...

  4. python json格式参数遍历所有key、value 及替换key对于的value

    1.对于接口自动化测试,一般接口以json形式发送返回,往往我们就需要遍历json文件中所有key,value以及修改替换key对于的value. 例如json发送/接收的文件: SendRegist ...

  5. 使用JQuery对页面进行绑值

    使用JQuery对页面进行绑值 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...

  6. Java学习之面向对象特性-----封装

    面向对象特性一.封装(Encapsulation)封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式.好处: 将变化隔离 便于使用 提高复用性 提高安全性封装原则: 将不需要对外提供的内容都隐 ...

  7. table td 溢出隐藏

    需要给table加一个属性:table-layout:fixed;

  8. JavaScript去除数组中重复的数字

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. 封装tab切换事件

    HTML <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <titl ...

  10. 递归,装饰器,python常用内置方法

    **递归**        def calc(n):            print(n)            if int(n / 2) == 0:  条件判断                r ...