动态加载之源码分析-openfire(一)

执迷不悟,那又如何。


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了。

有点长,




猜你喜欢

转载自blog.csdn.net/weixin_42132854/article/details/80265311
今日推荐