(转)OpenFire源码学习之四:openfire的启动流程
转:http://blog.csdn.net/huwenfeng_2011/article/details/43413233
openfire启动
ServerStarter
启动流程图:
启动的总入口在ServerStarter的main方法中。通过上图首先它会先加载它所需要的jar文件。最后通过Java反射机制将XMPPServer加入当前线程。
- Thread.currentThread().setContextClassLoader(loader);
- Class containerClass = loader.loadClass(
- "org.jivesoftware.openfire.XMPPServer");
- containerClass.newInstance();
当它获取当前执行的线程对象Thread.currentThread()然后设置为这个线程上下文类加载器,将loader加载进去。而loader是什么呢?再向上看它的源码:
- 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配置文件当中。
以下为代码清单
- 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文件属性之后,系统会测试数据库连接并生成数据表结构。通过一下方法完成操作
- DbConnectionManager.setConnectionProvider(conProvider);
然后检查数据库是否要更新
加载插件模块
of中所有的插件都以jar或war文件存在
- pluginManager = new PluginManager(pluginDir);
XMPPServer中 插件管理器(PluginManager)会添加插件的基本信息如:插件的实体、插件所在的目录、插件文件、插件监控等等
启动插件模块分为分为以下几个步骤:
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、加载启动模块
- 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()方法
统一初始化所有的插件代码清代:
- 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()这个方法来遍历已知的模块和启动它们。
- 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。这个监控器会定时检查插件目录是否有新的插件添加。
- 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。
- for (XMPPServerListener listener : listeners) {
- listener.serverStarted();
- }
这个通知消息说明服务器所有模块已经启动完成。这个时候就是监听消息的发送和接收了。但也有可能有些插件也会等待被装载。
(转)OpenFire源码学习之四:openfire的启动流程的更多相关文章
- Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Job Manager 启动
Job Manager 启动 https://t.zsxq.com/AurR3rN 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...
- Flink 源码解析 —— Standalone session 模式启动流程
Standalone session 模式启动流程 https://t.zsxq.com/EemAEIi 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0 ...
- Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Task Manager 启动
Task Manager 启动 https://t.zsxq.com/qjEUFau 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Ma ...
- Caddy源码阅读(二)启动流程与 Event 事件通知
Caddy源码阅读(二)启动流程与 Event 事件通知 Preface Caddy 是 Go 语言构建的轻量配置化服务器.https://github.com/caddyserver/caddy C ...
- Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍
最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...
- mybatis源码学习:插件定义+执行流程责任链
目录 一.自定义插件流程 二.测试插件 三.源码分析 1.inteceptor在Configuration中的注册 2.基于责任链的设计模式 3.基于动态代理的plugin 4.拦截方法的interc ...
- (转)OpenFire源码学习之七:组(用户群)与花名册(用户好友)
转:http://blog.csdn.net/huwenfeng_2011/article/details/43413651 Group 在openfire中的gorop——组,也可以理解为共享组.什 ...
- (转)OpenFire源码学习之二十七:Smack源码解析
转:http://blog.csdn.net/huwenfeng_2011/article/details/43484199 Smack Smack是一个用于和XMPP服务器通信的类库,由此可以实现即 ...
- (转)OpenFire源码学习之十八:IOS离线推送
转:http://blog.csdn.net/huwenfeng_2011/article/details/43458213 IOS离线推送 场景: 如果您有iOS端的APP,在会话聊天的时候,用户登 ...
随机推荐
- 【Flutter学习】组件学习之目录
01. Flutter组件-Layout-Container-容器 02. Flutter组件-Text-Text-文本 03. Flutter组件-Text-RichText-富文本 04. ...
- 为何使用Html5+CSS3
一:大多浏览器支持,低版本也没问题 我看点这方面的资料,是为了做手机应用网站(有三个方案,这个是备用方案),可以开发响应式网站,可以脱离开发平台进行跨平台. 在Html5网页中引入Modernizr, ...
- es6 常用的语法
1.es6 模块化 你import 和 export export default 为默认到处,而export能导出多个方法或变量. 2. es6——class与普通构造函数的区别 class的继承方 ...
- [NOIP模拟25]题解
A.字符串 Catalan数不能再裸了 #include<cstdio> #include<iostream> #include<cstring> using na ...
- 【已转移】【缓存与性能优化】一篇文章搞掂:Redis
本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 一.什么是Redis 全称: Remote Dictionary Server 远程字典服务器 实质: 一个缓存结构服务器或数据结 ...
- javascript闭包实现缓存小案例
/* * 闭包实现缓存 * 属性:有个键--值 --->所以可以将缓存数据存放在一个对象中 * 方法:缓存存储 setCache * 缓存的获取 getCache * */ function ...
- 爬虫(五)—— selenium模块启动浏览器自动化测试
目录 selenium模块 一.selenium介绍 二.环境搭建 三.使用selenium模块 1.使用chrome并设置为无GUI模式 2.使用chrome有GUI模式 3.查找元素 4.获取标签 ...
- mysql的时间存储格式
虽然mysql提供了datatime和timestamp两种存储时间的格式,但是如果设计较多计算,应存INT(11)类型.
- Tomcat启动脚本(3)setclasspath.bat
@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor lic ...
- Vue之自建管理后台(一)准备工作
完成最基础的Vue环境及新建一个vue项目. 一般来说,我们拿到一个项目需求或者得到一个需求的时候,第一件应该做的事情不是立马坐在电脑前面去写代码,如果你这么做的,好吧...我只能暂时认定你为一个刚上 ...