Javaでプラグインを処理するための良いパターンはありますか?

この質問は、前の質問私は尋ねました。

私が書いたコードの大部分は、その本質によって容易に拡張可能でなければならないAPIと関係しています。私と私のチームの残りの人たちが、プラグインを処理する方法、すなわち私たち自身のインターフェースを拡張するクラスと最終的な実装で対処することに取り組んでいる共通の問題は、ソリューションの原子的な部分のように感じるはずです。私は特に次のようなユースケース(車のアナロジーを使用する)で考えています。

Interface:

Car

提供された実装:

Ford
Audi

サードパーティの実装:

Toyota

通常、 CarDealer クラスは、 Car を明示的に宣言することなく Car の既存のすべての実装を認識する必要があります。構成ファイル。 Toyota のように、 CarDealer で自分自身を登録することができます。 >(または他の実装)は明示的に参照されるまで初期化されません。これはcatch22です。 Car の実装に注釈を付けてコードを実行し、関連するアノテーションを持つクラスを初期化する方法もありますが、これは恐ろしく重いリソースになる恐れがあります。

私たちはこの問題を持つ最初の人にはなれないと考えています。それでそこに解決するための既知のデザインパターンはありますか?

3
追加された 著者 Mot,

4 答え

Take a look at java.util.ServiceLoader. Essentially you create an interface, and all implementers of the service can then include a file /META-INF/services/ listing all implementations in their jar.

ServiceLoaderを使用すると、クラスパスで検出されたすべての実装をロードできます(たとえば、JDBC 4.0ではドライバをロードするためにClass.forName(...)の使用を取り除くためにドライバでもこれを使用する必要があります)。

3
追加された

あなたは依存性注入を探しているようです。 (ボーナス:Wikipediaは車の例を使用しています)

0
追加された

第三者のクラスだけの場所を指定し、Reflectionを使用してインスタンス化することができます。

または、カスタムクラスローダーを作成する

0
追加された
固定された場所を使うことは私たちが最終的に終わるかもしれませんが、私が望むよりも不器用です。カスタムクラスローダーの仕組みについて詳しく説明できますか?
追加された 著者 mikek,

この状況について話すとき、私の心には2つのことがあります:

    getName()と呼ばれる抽象実装(またはインタフェース)のメソッドを宣言します。この場合、トヨタは "Toyota"などを返します。次に、クラスパス全体をスキャンし、Carのサブクラスであるクラスを収集することを検討します(この方法を使用してください)。最後に、(static?)ファクトリメソッドを使用して、すべての "Car実装"を取得するか、名前で選択します。リフレクションを使用して新しいオブジェクトを取得する。

  1. OSGiと呼ばれるプラットフォームがあります(OSGiサービスを使用してプラグインを処理するために特別に作成されます)。 OSGiと通信するためにSpring DMを使用すると、かなり使いやすくなります。 FelixとEquinoxの2つの主な実装があります。

要約すると:プラットフォームを選択できる場合は、OSGiを選択します。もしあなたができなければ、私はクラスパスをスキャンしなければならないと思います。

0
追加された