Suppose BankController is your service. If you want to load its implementation dynamically from a dynamic path, create a new module layer and load the implementation.
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<Path> 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<String> 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); //create new instance of Implementation, in this case org.util.npci.coreconnect.CoreController implements org.util.npci.api.BankController final BankController bankController = ServiceLoader.load(moduleLayer, BankController.class); return bankController; } catch (Exception e) {BootLogger.info(e);} return null; }
source share