执迷不悟,那又如何。
openfire是我接触的第一款通讯开源框架,里面涉及到mina,插件开发更新等知识,项目完全开源,最近一直在学动态更新,偶尔想起以前读过openfire的源码,怕忘记,写一篇blog来复习一下其中的插件开发内容。与君分享。
openfire开源官网地址:http://www.igniterealtime.org/projects/openfire/index.jsp,
openfire github 地址:https://github.com/igniterealtime/Openfire
代码入口为;org.jivesoftware.openfire.starter.ServerStarter
private void start() { // Setup the classpath using JiveClassLoader try { // Load up the bootstrap container final ClassLoader parent = findParentClassLoader(); String libDirString = System.getProperty("openfire.lib.dir"); File libDir; if (libDirString != null) { // If the lib directory property has been specified and it actually // exists use it, else use the default libDir = new File(libDirString); if (!libDir.exists()) { Log.warn("Lib directory " + libDirString + " does not exist. Using default " + DEFAULT_LIB_DIR); libDir = new File(DEFAULT_LIB_DIR); } } else { libDir = new File(DEFAULT_LIB_DIR); } String adminLibDirString = System.getProperty("openfireHome"); if (adminLibDirString == null) { adminLibDirString = DEFAULT_ADMIN_LIB_DIR; } else { adminLibDirString = adminLibDirString+"/plugins/admin/webapp/WEB-INF/lib"; } File adminLibDir = new File(adminLibDirString); if (!adminLibDir.exists()) { Log.warn("Admin Lib Directory " + adminLibDirString + " does not exist. Web admin console may not work."); } ClassLoader loader = new JiveClassLoader(parent, libDir); Thread.currentThread().setContextClassLoader(loader); Class containerClass = loader.loadClass( "org.jivesoftware.openfire.XMPPServer"); containerClass.newInstance(); } catch (Exception e) { e.printStackTrace(); } }
先找到读取设置的lib路径,如果没有,采用默认的路径。然后用JiveClassLoader其中的class文件
最后加载org.jivesoftware.openfire.XMPPServer,然后newInstance,执行其中的静态方法开始运行
接下来看JiveClassLoader代码,他继承了urlclassloader
构造方法:
JiveClassLoader(ClassLoader parent, File libDir) throws MalformedURLException { super(new URL[] { libDir.toURI().toURL() }, parent); File[] jars = libDir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { boolean accept = false; String smallName = name.toLowerCase(); if (smallName.endsWith(".jar")) { accept = true; } else if (smallName.endsWith(".zip")) { accept = true; } return accept; } }); // Do nothing if no jar or zip files were found if (jars == null) { return; } // sort jars otherwise order differs between installations (e.g. it's not alphabetical) // order may matter if trying to patch an install by adding patch jar to lib folder Arrays.sort(jars); for (int i = 0; i < jars.length; i++) { if (jars[i].isFile()) { addURL(jars[i].toURI().toURL()); } } }
吧目录下的jar和zip加载进目录中,然后分析urlClassloader的addUrl和构造方法urlClassloader继承SecureClassLoader。
父类加载器为也就是先获取设置的classloader如果没有就是appclassloader
private ClassLoader findParentClassLoader() { ClassLoader parent = Thread.currentThread().getContextClassLoader(); if (parent == null) { parent = this.getClass().getClassLoader(); if (parent == null) { parent = ClassLoader.getSystemClassLoader(); } } return parent; }
在org.jivesoftware.openfire.XMPPServer中,先加载model
public void start() { try { initialize(); // Create PluginManager now (but don't start it) so that modules may use it File pluginDir = new File(openfireHome, "plugins"); pluginManager = new PluginManager(pluginDir); // If the server has already been setup then we can start all the server's modules if (!setupMode) { verifyDataSource(); // First load all the modules so that modules may access other modules while // being initialized loadModules(); // Initize all the modules initModules(); // Start all the modules startModules(); } // Initialize statistics ServerTrafficCounter.initStatistics(); // Load plugins (when in setup mode only the admin console will be loaded) pluginManager.start(); // Log that the server has been started String startupBanner = LocaleUtils.getLocalizedString("short.title") + " " + xmppServerInfo.getVersion().getVersionString() + " [" + JiveGlobals.formatDateTime(new Date()) + "]"; logger.info(startupBanner); System.out.println(startupBanner); started = true; // Notify server listeners that the server has been started for (XMPPServerListener listener : listeners) { listener.serverStarted(); } } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage(), e); System.out.println(LocaleUtils.getLocalizedString("startup.error")); shutdownServer(); } }
也急速在home下的model下,用loader加载model
loader为刚设置进去的loader,然后loader文件下的所有class
加载进去了 然后得到实例 最后放进一个map里面。然后初始化model
private void initModules() { for (Module module : modules.values()) { try { module.initialize(this); } catch (Exception e) { e.printStackTrace(); // Remove the failed initialized module this.modules.remove(module.getClass()); module.stop(); module.destroy(); logger.error(LocaleUtils.getLocalizedString("admin.error"), e); } } // Register modules with service discovery provides where applicable. for (Module module : modules.values() ) { // Service discovery info if (module instanceof ServerFeaturesProvider) { getIQDiscoInfoHandler().addServerFeaturesProvider( (ServerFeaturesProvider) module ); } if (module instanceof ServerIdentitiesProvider) { getIQDiscoInfoHandler().addServerIdentitiesProvider( (ServerIdentitiesProvider) module ); } if (module instanceof UserIdentitiesProvider) { getIQDiscoInfoHandler().addUserIdentitiesProvider( (UserIdentitiesProvider) module ); } // Service discovery items if (module instanceof ServerItemsProvider) { getIQDiscoItemsHandler().addServerItemsProvider( (ServerItemsProvider) module ); } if (module instanceof UserItemsProvider) { getIQDiscoItemsHandler().addUserItemsProvider( (UserItemsProvider) module); } } }
先初始化model,然后在将model根据接口装进不同的handler里面,然后开始执行模块,最后完成模块的加载
接下来就是pluginManager了。
有点长,