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
深入浅出JVM(八)之类加载器
深入浅出JVM(八)之类加载器
|
5月前
|
Java 编译器
Java健壮性 Java可移植性 JDK, JRE, JVM三者关系 Java的加载与执行原理 javac编译与JAVA_HOME环境变量介绍 Java中的注释与缩进 main方法的args参数
Java健壮性 Java可移植性 JDK, JRE, JVM三者关系 Java的加载与执行原理 javac编译与JAVA_HOME环境变量介绍 Java中的注释与缩进 main方法的args参数
50 1
|
4月前
|
存储 安全 Java
开发与运维引用问题之JVM类加载过程如何解决
开发与运维引用问题之JVM类加载过程如何解决
29 0
|
4月前
|
存储 算法 Java
JAVA程序运行问题之Java类加载到JVM中加载类时,实际上加载的是什么如何解决
JAVA程序运行问题之Java类加载到JVM中加载类时,实际上加载的是什么如何解决
|
5月前
|
安全 前端开发 Java
《JVM由浅入深学习【一】 》JVM由简入深学习提升(类加载过程+父子类加载过程+类加载器+双亲委派机制)
《JVM由浅入深学习【一】 》JVM由简入深学习提升(类加载过程+父子类加载过程+类加载器+双亲委派机制)
38 0
|
6月前
|
存储 Java 程序员
【JVM】类的声明周期(加载、连接、初始化)
【JVM】类的声明周期(加载、连接、初始化)
36 1
|
5月前
|
Java 编译器
全面解析JVM加载中初始化的时机
全面解析JVM加载中初始化的时机
|
6月前
|
Java
[JVM] Java类的加载过程
[JVM] Java类的加载过程
[JVM] Java类的加载过程
|
6月前
|
存储 监控 安全
JVM工作原理与实战(五):类的生命周期-加载阶段
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了类的生命周期、类的加载阶段等内容。
75 5
|
6月前
|
存储 缓存 安全
JVM 类的加载篇
JVM 类的加载篇
45 0