gpt4 book ai didi

java - 如何自定义 ServiceLoader 查找插件 jar 的位置

转载 作者:行者123 更新时间:2023-12-01 21:09:13 28 4
gpt4 key购买 nike

我有一个包含两个项目的多模块项目:CoreA。这个想法是每当 Core 启动时启动/运行 A。

如何自定义 ServiceLoader 以从核心查找并调用 Plugins 文件夹中的模块?

plugin-Project
+ Core
+ src\main\java
Core.java

+ A
+ src\main\java
A.java

+ Plugins

核心

public class Core extends Application {

private ServiceLoader<View> views;
private BorderPane mainBorderPane;

@Override
public void init() {
loadViews();
}

private void loadViews() {
views = ServiceLoader.load(View.class);
}

@Override
public void start(Stage stage) throws Exception {
stage.setTitle("Ui Application");

mainBorderPane = new BorderPane();
mainBorderPane.setTop(createMenuBar());

Scene scene = new Scene(new Group(), 800, 605);
scene.setRoot(mainBorderPane);

stage.setScene(scene);
stage.show();
}

private MenuBar createMenuBar() {
MenuBar menuBar = new MenuBar();
Menu viewMenu = new Menu("Views");
menuBar.getMenus().add(viewMenu);

ToggleGroup toggleGroup = new ToggleGroup();

views.forEach(v -> {
RadioMenuItem item = new RadioMenuItem(v.getName());
item.setToggleGroup(toggleGroup);
item.setOnAction(event -> {
Label label = new Label(v.getName());
mainBorderPane.setLeft(label);
mainBorderPane.setCenter(v.getView());
});
viewMenu.getItems().add(item);
});
return menuBar;
}

public static void main(String[] args) {
launch(args);
}

}

View.java

public interface View {

String getName();

Node getView();
}
<小时/>

场景

我正在开发的应用程序是一个多模块独立桌面应用程序。例如,Core 将在左侧保留一个 Pane (left-pane)。 left-pane 将接受来自任何实现名为 LeftPane 接口(interface)的模块的节点A 实现 LeftPane 接口(interface)。每当 Core 启动时,它应该扫描一个文件夹,在本例中为插件,并自动启动那里的所有包,包括 A,它将继续填充左 Pane 。

最佳答案

当然,最简单的方法是将插件放在类路径中。然后您可以简单地通过 ServiceLoader 访问接口(interface)。

或者您提供一种机制,它将检测特定位置的插件 jar 文件并将它们添加到类路径中。这是棘手的部分。实现此目的的一种方法是为您的应用程序使用自定义 ClassLoader,该应用程序允许将 jar 文件添加到类路径。

我选择了一种不同的方法,访问我的应用程序使用的ClassLoader的非公共(public)API:

private void addFile(File f) throws IOException // URL to your plugin jar file
{
addURL(f.toURI().toURL());
}

private void addURL(URL u) throws IOException
{
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class sysclass = URLClassLoader.class;

try {
Method method = sysclass.getDeclaredMethod("addURL", parameters);
method.setAccessible(true);
method.invoke(sysloader, new Object[] {u});
} catch (Throwable t) {
t.printStackTrace();
}

}

当插件 jar 文件位于类路径上时,您可以通过 ServiceLoader 访问公开的接口(interface)。让我用一个例子来说明这一点。暴露的接口(interface)可能如下所示:

/**
* Interface to allow plugins to contribute resource reference properties.
*/
public interface IResourcePropertyLoader {
/**
* Retrieve the base name for the additional text resource.
* @return
*/
String getResourcePropertyBaseName();
}

接口(interface)(也可以是基类)是核心应用程序的一部分。该插件有一个实现此接口(interface)的类。

接下来,您将查找该接口(interface)的所有实现:

ServiceLoader<ITextPropertyLoader> loader = ServiceLoader.load(ITextPropertyLoader.class, ClassLoader.getSystemClassLoader());

ServiceLoader 实现了 Iterable,因此您可以循环遍历所有实现:

for (ITextPropertyLoader textProperty : loader) {
final String textPropertyBaseName = textProperty.getTextPropertyBaseName();
System.out.println("Found text property with name: " + textPropertyBaseName);
}

另请查看Oracles documentation关于这个以及这个question

关于java - 如何自定义 ServiceLoader 查找插件 jar 的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41521595/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com