Best approach to dynamically load modules (classes) in Java

前端 未结 3 2228
南方客
南方客 2021-02-09 12:10

I\'m currently writing an application that requires to operate on different type of devices. My approach would be to make a \"modular\" application that can dynamically load dif

3条回答
  •  逝去的感伤
    2021-02-09 12:19

    There are two scenarios.

    1. Implementation jar's are on classpath
      In this scenario you can simply use ServiceLoader API (refer to @pdem answer)
    2. Implementation jar's not on classpath Lets Assume BankController is your interface and CoreController is your implementation.
      If you want to load its implementation dynamically from dynamic path,c create a new module layer and load class.

    Refer to the following piece of code:

            private final BankController loadController(final BankConfig config) {
                System.out.println("Loading bank with config : " + JSON.toJson(config));
                try {
                    //Curent ModuleLayer is usually boot layer. but it can be different if you are using multiple layers
                    ModuleLayer currentModuleLayer       = this.getClass().getModule().getLayer(); //ModuleLayer.boot();
                    final Set modulePathSet        = Set.of(new File("path of implementation").toPath());
                    //ModuleFinder to find modules 
                    final ModuleFinder moduleFinder      = ModuleFinder.of(modulePathSet.toArray(new Path[0]));
                    //I really dont know why does it requires empty finder.
                    final ModuleFinder emptyFinder       = ModuleFinder.of(new Path[0]);
                    //ModuleNames to be loaded
                    final Set  moduleNames       = moduleFinder.findAll().stream().map(moduleRef -> moduleRef.descriptor().name()).collect(Collectors.toSet());
                    // Unless you want to use URLClassloader for tomcat like situation, use Current Class Loader 
                    final ClassLoader loader             = this.getClass().getClassLoader();
                    //Derive new configuration from current module layer configuration
                    final Configuration  configuration   = currentModuleLayer.configuration().resolveAndBind(moduleFinder, emptyFinder, moduleNames);
                    //New Module layer derived from current modulee layer 
                    final ModuleLayer    moduleLayer     = currentModuleLayer.defineModulesWithOneLoader(configuration, loader);
                    //find module and load class Load class 
                    final Class       controllerClass = moduleLayer.findModule("org.util.npci.coreconnect").get().getClassLoader().loadClass("org.util.npci.coreconnect.CoreController");
                    //create new instance of Implementation, in this case org.util.npci.coreconnect.CoreController implements org.util.npci.api.BankController
                    final BankController bankController  = (BankController) controllerClass.getConstructors()[0].newInstance(config);
                    return bankController;
                } catch (Exception e) {BootLogger.info(e);}
                return null;
            }
    

提交回复
热议问题