Jvm-Sandbox源码分析--启动时加载模块

简介: 在上一篇Jvm-Sandbox源码分析--启动简析 简单介绍了一下jvm-sandbox启动流程,在这篇文章中我们来分析一下系统模块和用户的自定义模块在启动时,是怎么加载的。

前言

在上一篇Jvm-Sandbox源码分析--启动简析 简单介绍了一下jvm-sandbox启动流程,在这篇文章中我们来分析一下系统模块和用户的自定义模块在启动时,是怎么加载的。

在上一篇文章启动简析的最后,代码进入默认的模块管理类 DefaultCoreModuleManager.reset()方法

//DefaultCoreModuleManager
// 初始化加载所有的模块
public synchronized CoreModuleManager reset() throws ModuleException {

        // 1. 强制卸载所有模块
        unloadAll();

        // 2. 加载所有模块
        for (final File moduleLibDir : moduleLibDirArray) {
            // 用户模块加载目录,加载用户模块目录下的所有模块
            // 对模块访问权限进行校验
            if (moduleLibDir.exists() && moduleLibDir.canRead()) {
                //初始化模块目录加载器,传入模块lib目录和加载模式attach 默认加载模式就是attach
                new ModuleLibLoader(moduleLibDir, cfg.getLaunchMode())
                        .load(
                                new InnerModuleJarLoadCallback(),
                                new InnerModuleLoadCallback()
                        );
            } else {
                logger.warn("module-lib not access, ignore flush load this lib. path={}", moduleLibDir);
            }
        }

        return this;
    }

可以看到这部分代码主要做了两件事:强制卸载所有模块和加载所有模块,但是启动时候其实是没有加载模块的,所有这部分逻辑其实是会跳过,我们后续到通过命令卸载模块到时候再分析。

加载模块

这里加载的模块有两种类型:

  • 1.路径/Users/zhengmaoshao/sandbox/bin/../module 下的系统模块sandbox-mgr-module.jar
  • 2.路径/Users/zhengmaoshao/.sandbox-module 下的用户自定义模块
/**
     * 加载Module
     *
     * @param mjCb 模块文件加载回调
     * @param mCb  模块加载回掉
     */
    void load(final ModuleJarLoadCallback mjCb,
              final ModuleJarLoader.ModuleLoadCallback mCb) {

        // 开始逐条加载
        for (final File moduleJarFile : listModuleJarFileInLib()) {
            try {
                mjCb.onLoad(moduleJarFile);
                new ModuleJarLoader(moduleJarFile, mode).load(mCb);
            } catch (Throwable cause) {
                logger.warn("loading module-jar occur error! module-jar={};", moduleJarFile, cause);
            }
        }

    }

1.模块文件加载回调

/**
     * 用户模块文件加载回调
     */
    final private class InnerModuleJarLoadCallback implements ModuleJarLoadCallback {
        @Override
        public void onLoad(File moduleJarFile) throws Throwable {
            providerManager.loading(moduleJarFile);
        }
    }

最终会通过模块Jar文件加载链ModuleJarLoadingChain去加载文件
不过目前来看实现类都是空的,没有起到什么作用。

image

2.模块加载回调

//ModuleJarLoader.load
void load(final ModuleLoadCallback mCb) throws IOException {

        boolean hasModuleLoadedSuccessFlag = false;
        ModuleJarClassLoader moduleJarClassLoader = null;
        logger.info("prepare loading module-jar={};", moduleJarFile);
        try {
            moduleJarClassLoader = new ModuleJarClassLoader(moduleJarFile);

            final ClassLoader preTCL = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(moduleJarClassLoader);

            try {
                hasModuleLoadedSuccessFlag = loadingModules(moduleJarClassLoader, mCb);
            } finally {
                Thread.currentThread().setContextClassLoader(preTCL);
            }

        } finally {
            if (!hasModuleLoadedSuccessFlag
                    && null != moduleJarClassLoader) {
                logger.warn("loading module-jar completed, but NONE module loaded, will be close ModuleJarClassLoader. module-jar={};", moduleJarFile);
                moduleJarClassLoader.closeIfPossible();
            }
        }

    }

关键步骤:

  • 1.创建模块类加载器
  • 2.将当前线程的类加载器从沙箱类加载器设置成模块类加载器
  • 3.加载模块
  • 4.将当前线程的类加载器从模块类加载器设置成沙箱类加载器

3.加载模块过程

ModuleJarLoader的loadingModules方法中的关键步骤:

  • 1.通过ServiceLoader加载工具,从sandbox-mgr-module.jar加载沙箱环境模块接口Module的实现类。
    实际就是加载ControlModule,InfoModule,ModuleMgrModule 这三个用于内部操作的类。
    ServiceLoader<Module> moduleServiceLoader = ServiceLoader.load(Module.class, moduleClassLoader);
  • 2.调用模块加载回调onLoad方法,进入到真正进行模块加载的DefaultCoreModuleManager load方法。
      // 这里进行真正的模块加载
            load(uniqueId, module, moduleJarFile, moduleClassLoader);

DefaultCoreModuleManager load方法关键步骤:

  • 1.实例化模块业务对象,注入@resource资源,包括我们自定义Module中的@Resource资源都是在这个时候注入的,在ControlModule中即是沙箱配置信息ConfigInfo
    // 初始化模块信息
        final CoreModule coreModule = new CoreModule(uniqueId, moduleJarFile, moduleClassLoader, module);

        // 注入@Resource资源
        injectResourceOnLoadIfNecessary(coreModule);
  • 2.设置生命周期
  callAndFireModuleLifeCycle(coreModule, MODULE_LOAD);
  • 3.因为注解@Information中isActiveOnLoad表示是否在加载时候就激活模块,它的默认值是true, 所以会进入激活模块逻辑,这里需要注意,如果不希望启动时候就激活模块,则设置为false。模块只有在激活之后才能增强目标类。
//如果模块标记了加载时自动激活,则需要在加载完成之后激活模块
 markActiveOnLoadIfNecessary(coreModule);

在启动过程中系统模块和自定义模块到加载过程就分析完了,ControlModule,InfoModule,ModuleMgrModule 这三个系统模块提供了一些通过shell命令可以操作的方法。

而在我们通过sh sandbox.sh -p pid语句执行启动脚本sandbox.sh 的时候,最后会执行一个默认命令

# default
    sandbox_curl "sandbox-info/version"
    exit

这个命令就在刚刚加载的InfoModule类中

@Command("version")
public void version(final PrintWriter writer)

所以在我们完成加载之后,便会看到如下信息。

                    NAMESPACE : default
                      VERSION : 1.2.1
                         MODE : ATTACH
                  SERVER_ADDR : 0.0.0.0
                  SERVER_PORT : 60483
               UNSAFE_SUPPORT : ENABLE
                 SANDBOX_HOME : /Users/zhengmaoshao/sandbox/bin/..
            SYSTEM_MODULE_LIB : /Users/zhengmaoshao/sandbox/bin/../module
              USER_MODULE_LIB : /Users/zhengmaoshao/sandbox/sandbox-module;~/.sandbox-module;
          SYSTEM_PROVIDER_LIB : /Users/zhengmaoshao/sandbox/bin/../provider
           EVENT_POOL_SUPPORT : DISABLE
目录
相关文章
|
6月前
|
安全 Java 编译器
java------JVM之类加载和双亲委派机制
java------JVM之类加载和双亲委派机制
|
2月前
|
安全 Java 程序员
深入理解jvm - 类加载过程
深入理解jvm - 类加载过程
49 0
|
3月前
|
缓存 安全 前端开发
JVM(类的加载与ClassLoader、双亲委派机制)
JVM(类的加载与ClassLoader、双亲委派机制)
|
4月前
|
存储 缓存 前端开发
JVM(二):Class加载机制
JVM(二):Class加载机制
|
4月前
|
算法 Java 程序员
[JVM] 字节二面~简述垃圾回收以及类加载过程,别说八股文,我想看到你自己的理解
[JVM] 字节二面~简述垃圾回收以及类加载过程,别说八股文,我想看到你自己的理解
|
4月前
|
存储 Java
[JVM] 京东一面~说一下Java 类加载过程
[JVM] 京东一面~说一下Java 类加载过程
|
4月前
|
存储 前端开发 安全
浅谈 JVM 类加载过程
浅谈 JVM 类加载过程
42 0
|
6月前
|
存储 Java
【面试题精讲】JVM*类的生命周期*加载阶段
【面试题精讲】JVM*类的生命周期*加载阶段
|
7月前
|
存储 安全 Java
JVM- 类的加载过程、类加载器(付示例代码)
JVM- 类的加载过程、类加载器(付示例代码)
37 0
|
8月前
|
Java 关系型数据库 MySQL
阿里面试官(性能优化):描述一下jvm加载class文件的原理机制?
相信很多人对于性能优化都不陌生,为了获得更好的系统性能,或者是为了满足不断增加的业务需求。 都需要用到我们的性能调优。所以性能优化在面试中出现的频率特别高 楼主自认为自己对性能优化相关知识有很多了解,而且因为最近在找工作面试,所以单独复习了很多关于索引的知识。