動態加載之源碼分析-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了。

有點長,




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章