Jarslink源码解析-----ModuleLoaderImpl

moduleLoader实际上就是模块的“加载器”

我们从load方法开始

public Module load(ModuleConfig moduleConfig) {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Loading module: {}", moduleConfig);
        }
        List 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
            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 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文件加载。

 

你可能感兴趣的