在模块化应用程序组织之前,我有一个加载自定义的主JavaFX应用程序,它为主应用程序中的不同选项和可能性创建了多个库。
在旧的实现方式中,我只是发送新的库来更新,主应用程序从文件夹中读取所有库,它的工作方式就像一个护身符。但是在模块化系统中,如果我的应用程序想要使用我发送的新模块库,它需要更新它的module-info文件,我需要发送模块库和主应用程序的更新。想象一下,这就像是,chrome需要为创建的每个新插件发送浏览器更新。正如我所看到的,使用Java模块化系统,您不能创建模块化应用程序。
有没有办法在不更新主应用程序的情况下导入新的模块?
发布于 2019-05-17 21:50:24
Java有一个这样的类:ServiceLoader。
如果我们假设您有一个名为PluginProvider的“服务提供者”接口,其他模块可以通过将以下内容放入其各自的module-info.java描述符中来声明自己提供该服务:
provides com.john.myapp.PluginProvider with com.library.MyProvider;然后,您的应用程序将声明它在自己的module-info中使用该服务:
uses com.john.myapp.PluginProvider;您的应用程序代码将创建一个ModuleFinder来查找您期望这些插件模块所在的目录,然后将该ModuleFinder传递给一个Configuration,该ModuleLayer可用于为ServiceLoader创建一个ModuleLayer:
public class PluginLoader {
private final ServiceLoader<PluginProvider> loader;
public PluginLoader() {
Path pluginDir = Paths.get(System.getProperty("user.home"),
".local", "share", "MyApplication", "plugins");
ModuleLayer layer = PluginProvider.class.getModule().getLayer();
layer = layer.defineModulesWithOneLoader(
layer.configuration().resolveAndBind(
ModuleFinder.of(),
ModuleFinder.of(pluginDir),
Collections.emptySet()),
PluginProvider.class.getClassLoader());
loader = ServiceLoader.load(layer, PluginProvider.class);
}
public Stream<PluginProvider> getAll() {
return loader.stream();
}
public void reload() {
loader.reload();
}
}您甚至可能希望为新的或删除的文件watch插件目录:
try (WatchService watch = pluginDir.getFileSystem().newWatchService()) {
pluginDir.register(watch,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.OVERFLOW);
WatchKey key;
while ((key = watch.take()).isValid()) {
loader.reload();
key.reset();
}
}https://stackoverflow.com/questions/56169439
复制相似问题