Jvm-Sandbox Source Analysis--Loading modules at startup

Posted by zeberdeee on Fri, 06 Sep 2019 04:32:43 +0200

Preface

In the last article Jvm-Sandbox Source Analysis--Startup Analysis A brief introduction to the jvm-sandbox startup process is given. In this article, we will analyze how system modules and user-defined modules are loaded during startup.

At the end of the start of the profiling in the previous article, the code enters the default module management class DefaultCoreModuleManager.reset() method

//DefaultCoreModuleManager
// Initialize loading all modules
public synchronized CoreModuleManager reset() throws ModuleException {

        // 1. Force uninstallation of all modules
        unloadAll();

        // 2. Load all modules
        for (final File moduleLibDir : moduleLibDirArray) {
            // User module loads directory, loading all modules under user module directory
            // Verify module access rights
            if (moduleLibDir.exists() && moduleLibDir.canRead()) {
                //Initialize module directory loader, incoming module lib directory and load mode attach The default load mode is 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;
    }

You can see that this part of the code mainly does two things: forcing the uninstallation of all modules and loading all modules, but the module was not loaded at startup, all this logic is skipped, and we will analyze it later when the module is uninstalled by command.

Loading modules

There are two types of modules loaded here:

  • 1. System module sandbox-mgr-module.jar under path/Users/zhengmaoshao/sandbox/bin/. /module
  • 2. User-defined modules under Path/Users/Zhgmaoshao/.sandbox-module
/**
     * Load Module
     *
     * @param mjCb Module File Load Callback
     * @param mCb  Module Load Back
     */
    void load(final ModuleJarLoadCallback mjCb,
              final ModuleJarLoader.ModuleLoadCallback mCb) {

        // Start loading step by step
        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. Module File Load Callback

/**
     * User module file load callback
     */
    final private class InnerModuleJarLoadCallback implements ModuleJarLoadCallback {
        @Override
        public void onLoad(File moduleJarFile) throws Throwable {
            providerManager.loading(moduleJarFile);
        }
    }

The file is ultimately loaded through the module Jar file load chain ModuleJarLoadingChain
For now, however, the implementation classes are empty and have no effect.

2. Module Load Callback

//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();
            }
        }

    }

Key steps:

  • 1. Create a module class loader
  • 2. Set the class loader for the current thread from the application class loader to the module class loader
  • 3. Loading modules
  • 4. Set the class loader for the current thread from the module class loader to the application class loader

3. Loading module process

Key steps in the loadingModules method of ModuleJarLoader:

  • 1. Load the implementation class of the sandbox environment Module interface Module from sandbox-mgr-module.jar using the ServiceLoader load tool.
    It's actually loading the three classes ControlModule, InfoModule, ModuleMgrModule for internal operations.
    ServiceLoader<Module> moduleServiceLoader = ServiceLoader.load(Module.class, moduleClassLoader);
  • 2. Call the module load callback onLoad method to enter the DefaultCoreModuleManager load method that actually loads the module.
      // True module loading here
            load(uniqueId, module, moduleJarFile, moduleClassLoader);

DefaultCoreModuleManager load method key steps:

  • 1. Instantiate the Module business object and inject the @resource resource, including the @Resource resource in our custom Module, which is the sandbox configuration information ConfigInfo in the ControlModule
    // Initialize module information
        final CoreModule coreModule = new CoreModule(uniqueId, moduleJarFile, moduleClassLoader, module);

        // Inject @Resource Resource
        injectResourceOnLoadIfNecessary(coreModule);
  • 2. Set up the life cycle
  callAndFireModuleLifeCycle(coreModule, MODULE_LOAD);
  • 3. Because the default value for activating the module isActiveOnLoad at load time in comment@Information is true, the activation part code will be entered
//If the module is marked to activate automatically when loading, you need to activate the module after loading is complete
 markActiveOnLoadIfNecessary(coreModule);

During startup, system modules and custom modules are analyzed when loading. The three system modules, ControlModule, InfoModule and ModuleMgrModule, provide some methods that can be operated on by shell commands.

When we execute the startup script sandbox.sh through the sh sandbox.sh -p pid statement, a default command is executed.

# default
    sandbox_curl "sandbox-info/version"
    exit

This command is in the InfoModule class that just loaded

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

So when we finish loading, you'll see the following information.

                    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

Topics: Java jvm shell