Service Provider Interface(SPI) と Application Programming Interface(API) の違いは何ですか?
具体的には、Javaライブラリの場合、APIおよび/またはSPIになっているのはなぜですか?
別の言い方をすれば、APIは特定のクラス/メソッドが何をするのかを示し、SPIは準拠するために何をする必要があるかを示します。
通常、APIとSPIは別々です。たとえば、JDBCでは Driver
class はSPIの一部です。単にJDBCを使用する場合は、直接使用する必要はありませんが、JDBCドライバを実装する全員がそのクラスを実装する必要があります。
ただし、重複する場合があります。 Connection
インターフェース はbothSPIおよびAPI:JDBCドライバーを使用する場合は定期的に使用しますJDBCドライバーの開発者が実装する必要があります。
Effective Java、2nd Editionから:
サービスプロバイダーフレームワークは、複数のサービスプロバイダーがサービスを実装するシステムであり、システムは実装をクライアントから利用可能にし、実装から分離します。
サービスプロバイダーフレームワークには3つの重要なコンポーネントがあります。プロバイダーが実装するサービスインターフェイス。システムが実装を登録するために使用し、クライアントに実装を提供するプロバイダー登録API。クライアントがサービスのインスタンスを取得するために使用するサービスアクセスAPI。通常、サービスアクセスAPIでは、クライアントがプロバイダーを選択するための基準を指定することを許可していますが、必須ではありません。このような仕様がない場合、APIはデフォルトの実装のインスタンスを返します。サービスアクセスAPIは、サービスプロバイダーフレームワークの基盤を形成する「柔軟な静的ファクトリ」です。
サービスプロバイダーフレームワークのオプションの4番目のコンポーネントは、サービスプロバイダーインターフェイスであり、プロバイダーは、サービス実装のインスタンスを作成するために実装します。サービスプロバイダーインターフェイスがない場合、実装はクラス名で登録され、リフレクションでインスタンス化されます(項目53)。 JDBCの場合、Connectionはサービスインターフェイスの役割を果たし、DriverManager.registerDriverはプロバイダー登録API、DriverManager.getConnectionはサービスアクセスAPI、Driverはサービスプロバイダーインターフェイスです。
サービスプロバイダーフレームワークパターンには多くのバリエーションがあります。たとえば、サービスアクセスAPIは、アダプターパターン[Gamma95、p。を使用して、プロバイダーに必要なインターフェイスよりも豊富なサービスインターフェイスを返すことができます。 139]。次に、サービスプロバイダーインターフェイスとデフォルトプロバイダーを使用した簡単な実装を示します。
// Service provider framework sketch
// Service interface
public interface Service {
... // Service-specific methods go here
}
// Service provider interface
public interface Provider {
Service newService();
}
// Noninstantiable class for service registration and access
public class Services {
private Services() { } // Prevents instantiation (Item 4)
// Maps service names to services
private static final Map<String, Provider> providers =
new ConcurrentHashMap<String, Provider>();
public static final String DEFAULT_PROVIDER_NAME = "<def>";
// Provider registration API
public static void registerDefaultProvider(Provider p) {
registerProvider(DEFAULT_PROVIDER_NAME, p);
}
public static void registerProvider(String name, Provider p){
providers.put(name, p);
}
// Service access API
public static Service newInstance() {
return newInstance(DEFAULT_PROVIDER_NAME);
}
public static Service newInstance(String name) {
Provider p = providers.get(name);
if (p == null)
throw new IllegalArgumentException(
"No provider registered with name: " + name);
return p.newService();
}
}
APIはApplication Programming Interfaceの略で、APIは何らかのソフトウェアまたはプラットフォームによって提供されるサービス/機能にアクセスするための手段です。
SPIは、Service Provider Interfaceを表します。SPIは、ソフトウェアまたはプラットフォームの動作を注入、拡張、または変更する方法です。 。
APIは通常、クライアントがサービスにアクセスするためのターゲットであり、次のプロパティがあります:
-> APIは、特定の動作や出力を達成するためにサービスにアクセスするプログラム的な方法です
-> APIの進化の観点から、追加はクライアントにとってまったく問題ありません
->しかし、クライアントの期待が完全に低下しているため、適切な通信がない限り、APIはクライアントによって一度使用され、変更/削除することはできません(またすべきではありません)
他の部分のSPIはプロバイダーを対象としており、次のプロパティがあります:
-> SPIは、ソフトウェアまたはプラットフォームの動作を拡張/変更する方法です(プログラム可能とプログラム可能)
-> SPIの進化はAPIの進化とは異なります。SPIの削除は問題ではありません
-> SPIインターフェースの追加は問題を引き起こし、既存の実装を破壊する可能性があります
詳細については、ここをクリックしてください。 サービスプロバイダーインターフェイス
APIとSPIの違いは、APIがさらに具体的な実装を提供するときに発生します。その場合、サービスプロバイダーはいくつかのAPI(SPIと呼ばれる)を実装する必要があります
例はJNDIです。
JNDIは、コンテキスト検索用のインターフェースといくつかのクラスを提供します。コンテキストを検索するデフォルトの方法は、IntialContextで提供されます。このクラスは、プロバイダ固有の実装にSPIインターフェイス(NamingManagerを使用)を内部的に使用します。
理解を深めるには、以下のJNDIアーキテクチャを参照してください。
NetBeansのFAQ: SPIとは何ですか?APIとはどう違いますか
APIは一般的な用語-Application Programming Interfaceの頭字語です-これは、ソフトウェアの一部が公開する何か(Javaでは通常、いくつかのJavaクラス)を意味し、他のソフトウェアとの通信を可能にします。
SPIはService Provider Interfaceの略です。ライブラリは、アプリケーション(またはAPIライブラリ)によって呼び出され、通常アプリケーションが実行できることを変更するクラスを提供している状況に固有のAPIになり得るすべてのもののサブセットです。
古典的な例はJavaMailです。そのAPIには2つの側面があります。
- API側—メールクライアントを作成している場合、またはメールボックスを読み取りたい場合に呼び出す
- JavaMailがニュースやIMAPサーバーなどの新しい種類のサーバーと通信できるようにするワイヤープロトコルハンドラーを提供している場合は、SPI側
APIのユーザーがSPIクラスを見たり、話したりする必要はほとんどありません。逆の場合も同様です。
NetBeansでは、SPIという用語を見ると、通常、実行時にモジュールが注入できるクラスについて話しているため、NetBeansは新しいことを実行できます。たとえば、バージョン管理システムを実装するための一般的なSPIがあります。さまざまなモジュールが、CVS、Subversion、Mercurial、およびその他のリビジョン管理システム用のそのSPIの実装を提供します。ただし、ファイルを処理するコード(API側)は、バージョン管理システムがあるかどうか、またはそれが何であるかを気にする必要はありません。
サービスプロバイダーインターフェイスは、すべてのプロバイダーが実装する必要があるサービスインターフェイスです。既存のプロバイダー実装のいずれも機能しない場合は、独自のサービスプロバイダーを作成し(サービスインターフェイスを実装)、どこかに登録する必要があります(Romanによる有用な投稿を参照)。
サービスインターフェースの既存のプロバイダー実装を再利用する場合、基本的にはその特定のプロバイダーのAPIを使用します。これには、サービスインターフェースのすべてのメソッドと独自のいくつかのパブリックメソッドが含まれます。 SPIの外部でプロバイダーAPIのメソッドを使用している場合、プロバイダー固有の機能を使用しています。
SPIは、APIの特定の機能を実装し、それ自体をサービスルックアップメカニズムを介して利用可能として登録することにより、より大きなシステムに挿入されると考えられます。 APIはエンドユーザーアプリケーションコードによって直接使用されますが、SPIコンポーネントを統合する場合があります。カプセル化と直接使用の違いです。
あまりハイライトされていないように見えますが、API/SPIスプリットの存在の理由を理解するために非常に重要な側面が1つあります。
API/SPI分割は、プラットフォームの進化が予想される場合にのみ必要です。APIを記述し、 "know"今後の改善は必要ありません。コードを2つの部分に分割する本当の理由はありません(クリーンなオブジェクトデザインを作成する以外に)。
しかし、これはほとんどあり得ず、人々は将来の要件とともにAPIを下位互換性のある方法で進化させる自由が必要です。
上記のすべては、他の人が使用および/または拡張するプラットフォームを構築していることを前提としており、すべてのクライアントコードが制御されているため、必要に応じてリファクタリングできる独自のAPIではないことに注意してください
よく知られているJavaオブジェクトCollection
およびCollections
の1つに表示します。
API:Collections
は、ユーティリティの静的メソッドのセットです。多くの場合、APIオブジェクトを表すクラスはfinal
として定義されます。これは、クライアントが「実装」できず、依存できるその静的メソッド、たとえば「呼び出し」.
Collections.emptySet();
すべてのクライアントは "calling"であるが "implementing"ではないため、JDKの作成者は JDKの将来のバージョンでは、Collections
オブジェクトに新しいメソッドを自由に追加できます。彼らは、おそらく何百万の使用法があるとしても、それがクライアントを壊さないことを確信できます。
SPI:Collection
は、だれでも自分のバージョンを実装できることを意味するインターフェイスです。したがって、JDKの作成者は、独自のCollection
実装(*)を作成したすべてのクライアントを中断するため、新しいメソッドをitに追加できません。
通常、追加のメソッドを追加する必要がある場合、新しいインターフェイス、たとえば前者を拡張するCollection2
を作成する必要があります。 SPIクライアントは、SPIの新しいバージョンに移行して追加のメソッドを実装するか、古いバージョンを使用するかを決定できます。
あなたはすでにポイントを見たかもしれません。両方の要素を1つのクラスに結合すると、APIは追加からブロックされます。また、優れたJava APIおよびフレームワークがabstract class
を公開しないのは、下位互換性に関して将来の進化を妨げるためです。
それでも不明な点がある場合は、 このページ を確認することをお勧めします。これにより、上記の詳細が説明されます。
(*)これは、インターフェースで定義されたdefault
メソッドの概念を導入するJava 1.8まで真であることに注意してください。
Javaの世界では、さまざまなテクノロジーがモジュール式であり、アプリケーションサーバーに「プラグイン可能」であることを意図しています。それからの間に違いがあります
このようなテクノロジーの2つの例は、JTA(トランザクションマネージャー)とJCA(JMSまたはデータベースのアダプター)です。しかし、他にもあります。
そのようなプラグ可能な技術の実装者は、アプリでプラグ可能になるようにSPIを実装する必要があります。エンドユーザーアプリケーションが使用するAPIを提供します。 JCAの例は、SPIの一部である ManagedConnection インターフェースと、エンドユーザーAPIの一部である Connection です。