Java 9 ServiceLoader运行时模块的加载和替换

时间:2018-04-04 07:02:23

标签: java runtime java-9 serviceloader

我刚刚阅读了Java 9模块系统,我想问一下ServiceLoader。有没有办法在应用程序启动时添加服务实现?删除一些服务实现怎么样?

用例:我会有一些计算某些东西的应用程序。计算算法将在某些服务(Java 9模块)中定义。是否有任何步骤可以在不停止应用程序的情况下替换此算法?我何时更换罐子只是计算失败而且我需要捕获错误并在模块加载完成后重新启动?

是否有其他项目可以支持此类用例?

1 个答案:

答案 0 :(得分:0)

让我们假设BankController是您的服务。 如果要从动态路径动态加载其实现,请创建一个新的模块层并加载实现。

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;
}