我一直在开发一个带有基于插件的系统的软件,用户可以在其中编写自己的插件。我对 JMPS 很陌生,但我想使用 JMPS 而不是 OSGi 来实现这一点。制作了一个单独的 API 模块,甚至创建了一个测试插件。
插件以文件名“someplugin.jar”存储在目录中。
如何在运行时加载所有这些 jar(它们都不是自动模块,而是带有 module-info.class 的明确定义的模块)?我想在运行时动态加载它们的原因是用户可以选择更改目录来搜索插件,并且无需重新启动应用程序即可更改它。
要动态加载模块,您需要定义一个新的ModuleLayer。新的模块层将继承引导层:
这意味着在引导层(主模块所在的位置)中,您不能直接引用插件层中的类。但是,您可以通过以下方式使用插件层services.
以下是您可以用作起点的代码:
Path pluginsDir = Paths.get("plugins"); // Directory with plugins JARs
// Search for plugins in the plugins directory
ModuleFinder pluginsFinder = ModuleFinder.of(pluginsDir);
// Find all names of all found plugin modules
List<String> plugins = pluginsFinder
.findAll()
.stream()
.map(ModuleReference::descriptor)
.map(ModuleDescriptor::name)
.collect(Collectors.toList());
// Create configuration that will resolve plugin modules
// (verify that the graph of modules is correct)
Configuration pluginsConfiguration = ModuleLayer
.boot()
.configuration()
.resolve(pluginsFinder, ModuleFinder.of(), plugins);
// Create a module layer for plugins
ModuleLayer layer = ModuleLayer
.boot()
.defineModulesWithOneLoader(pluginsConfiguration, ClassLoader.getSystemClassLoader());
// Now you can use the new module layer to find service implementations in it
List<Your Service Interface> services = ServiceLoader
.load(layer, <Your Service Interface>.class)
.stream()
.map(Provider::get)
.collect(Collectors.toList());
// Do something with `services`
...
模块层被认为是一个高级主题,但我并不认为它真的很困难。您需要理解的唯一关键点是模块层是继承的。这意味着从子层中,您只能引用父层的类,反之亦然。要执行相反的操作,您必须使用控制反转它是在Java模块系统中实现的ServiceLoader
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)