0

CoreA の2 つのプロジェクトを含むマルチモジュール プロジェクトがあります。アイデアは、コアが起動されるたびに 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();
}

シナリオ

私が取り組んでいるアプリケーションは、マルチモジュールのスタンドアロン デスクトップ アプリケーションです。たとえば、コアは左側にペインを保持します(左ペイン)nodesleft-pane は、 と呼ばれるインターフェースを実装するすべてのモジュールから受け入れますLeftPaneAはインターフェイスを実装しLeftPaneます。Core が起動されるたびに、フォルダー (この場合はプラグイン) をスキャンし、A を含むすべてのバンドルを自動的に開始して、左側のペインに入力します。

4

1 に答える 1

3

もちろん、最も簡単な方法は、プラグインを既にクラスパスに置くことです。その後、 を介してインターフェイスに簡単にアクセスできますServiceLoader

または、プラグイン jar ファイルを特定の場所で検出し、それらをクラスパスに追加するメカニズムを提供します。これはトリッキーな部分です。ClassLoaderこれを行う 1 つの方法は、jar ファイルをクラスパスに追加できるアプリケーションのカスタムを使用することです。

ClassLoaderアプリケーションで使用されている非公開 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 to allow plugins to contribute resource reference properties.
 */
public interface IResourcePropertyLoader {
    /**
     * Retrieve the base name for the additional text resource.
     * @return
     */
    String getResourcePropertyBaseName();
}

インターフェイス (基本クラスの場合もあります) は、コア アプリケーションの一部です。プラグインには、このインターフェースを実装するクラスがあります。

次に、そのインターフェースのすべての実装を検索します。

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

ServiceLoaderimplementsであるため、すべてのIterable実装をループできます。

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

これとこの質問に関するオラクルのドキュメントもご覧ください

于 2017-01-07T12:58:16.190 に答える