Jarslink源碼解析-----ModuleLoaderImpl

moduleLoader實際上就是模塊的“加載器”

我們從load方法開始

public Module load(ModuleConfig moduleConfig) {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Loading module: {}", moduleConfig);
        }
        List<String> tempFileJarURLs = moduleConfig.getModuleUrlPath();
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Local jars: {}", tempFileJarURLs);
        }

        ConfigurableApplicationContext moduleApplicationContext = loadModuleApplication(moduleConfig, tempFileJarURLs);

        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Loading module  complete:{}", moduleConfig);
        }
        return new SpringModule(moduleConfig, moduleConfig.getVersion(), moduleConfig.getName(),
                moduleApplicationContext);
    }

我們可以看到moduleLoader首先調用了loadModuleApplication方法,下面我們繼續看此方法

private ConfigurableApplicationContext loadModuleApplication(ModuleConfig moduleConfig, List<String>
            tempFileJarURLs) {
        ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
        //獲取模塊的ClassLoader
        ClassLoader moduleClassLoader = new ModuleClassLoader(moduleConfig.getModuleUrl(), applicationContext
                .getClassLoader(), getOverridePackages(moduleConfig));

        try {
            //把當前線程的ClassLoader切換成模塊的
            Thread.currentThread().setContextClassLoader(moduleClassLoader);

            ConfigurableApplicationContext context;
            Properties properties = getProperties(moduleConfig);
            Set<String> scanBase = moduleConfig.getScanPackages();
            //註解方式加載bean
            if (!scanBase.isEmpty()) {
                ModuleAnnotationApplicationContext annotationConfigApplicationContext = new
                        ModuleAnnotationApplicationContext(properties);
                annotationConfigApplicationContext.scan(scanBase.toArray(new String[0]));
                context = annotationConfigApplicationContext;
            } else {
                //XML方式加載bean
                ModuleXmlApplicationContext moduleApplicationContext = new ModuleXmlApplicationContext();
                moduleApplicationContext.setProperties(properties);
                moduleApplicationContext.setConfigLocations(findSpringConfigs(tempFileJarURLs, moduleClassLoader,
                        getExclusionConfigeNameList(properties)));
                context = moduleApplicationContext;
            }
            context.setParent(applicationContext);
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("module {}:{} allow current process to override bean in module", moduleConfig.getName(),
                        moduleConfig.getVersion());
            }
            ((DefaultResourceLoader) context).setClassLoader(moduleClassLoader);
            context.refresh();
            return context;
        } catch (Throwable e) {
            CachedIntrospectionResults.clearClassLoader(moduleClassLoader);
            throw Throwables.propagate(e);
        } finally {
            //還原當前線程的ClassLoader
            Thread.currentThread().setContextClassLoader(currentClassLoader);
        }
    }

上面這段代碼可以說是jarslink的核心部分,此方法初始化了模塊自己的ClassLoader,初始化Spring Application Context,同時要設置當前線程上下文的ClassLoader爲模塊的ClassLoader,這樣就保證了實例隔離以及類隔離。

初始化上下文的時候,jarslink只能採用註解加載或者xml方式加載,不過在實際工程中,我們可以使用@ImportResource等註解引入我們的xml,值得注意的是,springboot中使用的yml以及propertise方式初始化在jarslink中是無法使用的,需要修改爲bean加載或者xml文件加載。

 

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