単純なJava「サービスプロバイダーフレームワーク」?
-
16-09-2019 - |
質問
議論されているように「サービスプロバイダーフレームワーク」を参照してください 効果的なJavaの第2章, 、これは、私が抱えている問題を処理する正確な方法のように思えます。 String
どのサービスを選択します Configuration
オブジェクト(本質的にXMLスニペット):
しかし、個々のサービスプロバイダー(たとえば、デフォルトプロバイダーの束やいくつかのカスタムプロバイダー)に自分自身を登録するにはどうすればよいですか?
interface FooAlgorithm
{
/* methods particular to this class of algorithms */
}
interface FooAlgorithmProvider
{
public FooAlgorithm getAlgorithm(Configuration c);
}
class FooAlgorithmRegistry
{
private FooAlgorithmRegistry() {}
static private final Map<String, FooAlgorithmProvider> directory =
new HashMap<String, FooAlgorithmProvider>();
static public FooAlgorithmProvider getProvider(String name)
{
return directory.get(serviceName);
}
static public boolean registerProvider(String name,
FooAlgorithmProvider provider)
{
if (directory.containsKey(name))
return false;
directory.put(name, provider);
return true;
}
}
たとえば、カスタムクラスを作成した場合、myfooalgorithmとmyfooalgorithmprovider fooalgorithmを実装し、jarに配布する場合、レジスタプロバイダーを自動的に呼び出すか、アルゴリズムを使用するクライアントプログラムを明示的に呼び出す必要があるクライアントプログラムをfooalgorithmistry.registerprovider(Registerprovider(RegisterProvider)に呼び出す方法がありますか? )彼らが使いたいクラスごとに?
解決
Meta-inf/services/fully.aqualified.classnameを作成してそこにリストする必要があると思いますが、スペックを覚えていません(jarファイルの仕様 また これ).
Java Architectの実用的なAPIデザインの自白 ブック第8章はSPIに関するものです。
Serviceloaderは、利用可能な実装をリストするのに役立つ場合があります。たとえば、PersistenceProviderインターフェイスを使用してください。
ServiceLoader<PersistenceProvider> loader =
ServiceLoader.load(PersistenceProvider.class);
Iterator<PersistenceProvider> implementations = loader.iterator();
while(implementations.hasNext()) {
PersistenceProvider implementation = implementations.next();
logger.info("PersistenceProvider implementation: " + implementation);
}
他のヒント
クライアントジャーに、以前に呼び出されることがわかっているクラス内の静的イニシャルイザーブロックにプロバイダーを登録させることができます FooAlgorithmRegistry.getProvider()
, 、 何かのようなもの:
static {
FooAlgorithmRegistry.registerProvider("test", new MyFooAlgorithmProvider());
}
しかし、工場のアクセサの前に、これが実行されることを保証する方法を見つけるのは非常に難しいかもしれません(クラスが最初にロードされたときに一度だけ実行されることが保証されます)。