8

プラグインを動的にロードできるアプリケーションを作りたいのですが、インターネット上に文献が見つかりません。

難しいのは、事前に名前がわからないことです。

たとえば、プラグインインターフェイスがあります。

public interface Plugin {
    public static Plugin newPlugin();
    public void executePlugin(String args[]);
}

jarファイル内のプラグインを実装するすべてのクラスがリストにインスタンス化されるように:

Method method = classToLoad.getMethod ("newPlugin");
mylist.add(method.invoke(null);
  1. 最初の問題は、インターフェイスに静的メソッドを含めることができないことです。
  2. 2番目の問題は、インターフェイスを実装するすべてのクラスを見つける方法がわからないことです。

ご協力いただきありがとうございます。

4

2 に答える 2

27

したがって、実行時に特定のインターフェイス(たとえば)を実装するクラスを動的に検出したいようですPlugin。これには基本的に2つの選択肢があります。

  1. osgiのようなコンポーネントフレームワークを使用する
  2. Javaの内部検出プロセスを使用する(ServiceLoader

osgi(小さなものも)に関する優れたチュートリアルがたくさんあるので、ここでは詳しく説明しません。Javaの内部検出プロセスを使用するには、次のことを行う必要があります。

  • 発見したいすべての「新しい」クラスをjarファイルにバンドルします
  • jarファイルに新しいファイルを作成します。META-INF/services/package.Pluginここで完全なパッケージ修飾子を使用する必要があります
  • このファイルは単純なテキストファイルでありPlugin、そのjarファイルに実装されている各クラスの完全修飾名が含まれています。
  • そのjarファイルを(すでに実行されている可能性のある)アプリケーションのクラスパスに配置します
  • サービスを発見する:

サービス検出は次のように行われます。

ServiceLoader<Plugin> loader = ServiceLoader.load(Plugin.class)
for (Plugin p : loader) {
    // do something with the plugin
}

詳細については、http: //docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.htmlをご覧ください。

インターフェイスの静的メソッドについて:不可能。静的メソッドはクラスのインスタンスなしでアクセス可能であり、インターフェースは機能なしでメソッドを定義するだけなので、そのセマンティクスもやや奇妙です。したがって、staticは呼び出しを許可しますInterface.doSomething()が、インターフェースは機能を定義しませんが、これは混乱を招きます。

編集:

メタファイルに何を含めるべきかについての説明を追加

于 2012-12-13T23:41:37.303 に答える
2

最初の問題に関しては、インターフェイスに静的メソッドを含めることができないということですが、私の提案は、単にインターフェイスにマーカーがあり、それをインスタンス化することです。

プラグインインターフェイスは次のようになります。

public interface Plugin {
  public void executePlugin(String args[]);
}

そして、あなたは次のことができます:

if (someClass instanceOf Plugin) {
  mylist.add(someClass.newInstance());
}

これは2番目の質問につながります。どのようにしてsomeClass参照を取得しますか。 クラスパスに特定のインターフェイスを実装しているすべてのクラスを見つける標準的な方法はありませんが、クラスパス内のjarをスキャンして、特定のファイルがjar内のパスを介して完全修飾名であると判断した場合、メソッドを使用してクラスを実体化します。.classClass.forName()

擬似コードでは、次のようになります。

for each jar in your classpath {
  for each file in JarFile {
    if (file ends with .class) {
       materialize class using Class.forName
     } 
  }
}

インスタンスを使用Classすると、インターフェースが実装されているかどうかを確認できPluginます。

また、プラグインにコンテキストを追加する必要がある場合は、デフォルトのコンストラクターを使用する代わりに、コンテキストオブジェクトを受け取るすべてのプラグインにコンストラクターを作成できることにも注意してください。このような場合、使用する代わりに、newInstance()リフレクションを介して必要な引数を持つコンストラクターを取得する必要があります。

于 2012-12-13T23:48:38.680 に答える