我一直在开发带有基于插件的系统的软件,用户可以在其中编写自己的插件。我对 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`
...
Run Code Online (Sandbox Code Playgroud)
模块层被认为是一个高级主题,但我觉得它并不难。您需要了解的唯一关键点是模块层是继承的。这意味着从子层,您只能引用父层的类,反之则不能。做相反的事情,你必须使用在 Java 模块系统中实现的控制反转ServiceLoader。
| 归档时间: |
|
| 查看次数: |
358 次 |
| 最近记录: |