Was ist der Unterschied zwischen Service Provider Interface (SPI) und Application Programming Interface (API) ?
Was macht Java-Bibliotheken zu einer API und / oder SPI?
Was ist der Unterschied zwischen Service Provider Interface (SPI) und Application Programming Interface (API) ?
Was macht Java-Bibliotheken zu einer API und / oder SPI?
Antworten:
Anders ausgedrückt, die API sagt Ihnen, was eine bestimmte Klasse / Methode für Sie tut, und die SPI sagt Ihnen, was Sie tun müssen, um sich anzupassen.
Normalerweise sind API und SPI getrennt. In JDBC ist die Driver
Klasse beispielsweise Teil des SPI: Wenn Sie JDBC einfach verwenden möchten, müssen Sie es nicht direkt verwenden, aber jeder, der einen JDBC-Treiber implementiert, muss diese Klasse implementieren.
Manchmal überlappen sie sich jedoch. Die Connection
Schnittstelle ist sowohl SPI als auch API: Sie verwenden sie routinemäßig, wenn Sie einen JDBC-Treiber verwenden, und sie muss vom Entwickler des JDBC-Treibers implementiert werden.
@SomeAnnotation
meine Klasse erweitern muss, um sie von einem Framework übernehmen zu können, wird diese Anmerkungsklasse SomeAnnotation.class
dann als Teil des SPI betrachtet, obwohl ich sie technisch nicht erweitere oder implementiere?
Von Effective Java, 2. Ausgabe :
Ein Service Provider Framework ist ein System, in dem mehrere Service Provider einen Service implementieren. Das System stellt die Implementierungen seinen Clients zur Verfügung und entkoppelt sie von den Implementierungen.
Es gibt drei wesentliche Komponenten eines Dienstanbieter-Frameworks: eine Dienstschnittstelle, die von Anbietern implementiert wird; eine Anbieterregistrierungs-API, mit der das System Implementierungen registriert und Clients Zugriff auf diese gewährt; und eine Dienstzugriffs-API, mit der Clients eine Instanz des Dienstes abrufen. Die Servicezugriffs-API ermöglicht, erfordert jedoch nicht, dass der Client einige Kriterien für die Auswahl eines Anbieters angibt. In Ermangelung einer solchen Spezifikation gibt die API eine Instanz einer Standardimplementierung zurück. Die Service Access API ist die „flexible statische Factory“, die die Grundlage für das Service Provider Framework bildet.
Eine optionale vierte Komponente eines Dienstanbieter-Frameworks ist eine Dienstanbieter-Schnittstelle, die Anbieter implementieren, um Instanzen ihrer Dienstimplementierung zu erstellen. In Abwesenheit einer Dienstanbieterschnittstelle werden Implementierungen nach Klassennamen registriert und reflektierend instanziiert (Punkt 53). Im Fall von JDBC spielt Connection die Rolle der Dienstschnittstelle, DriverManager.registerDriver ist die API für die Anbieterregistrierung, DriverManager.getConnection ist die API für den Dienstzugriff und Driver ist die Schnittstelle für den Dienstanbieter.
Es gibt zahlreiche Varianten des Dienstanbieter-Framework-Musters. Beispielsweise kann die Dienstzugriffs-API eine umfangreichere Dienstschnittstelle als die vom Anbieter geforderte zurückgeben, indem das Adaptermuster verwendet wird [Gamma95, S. 139]. Hier ist eine einfache Implementierung mit einer Dienstanbieterschnittstelle und einem Standardanbieter:
// 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();
}
}
Der Unterschied zwischen API und SPI ergibt sich, wenn eine API zusätzlich einige konkrete Implementierungen bereitstellt. In diesem Fall muss der Dienstanbieter einige APIs (SPI genannt) implementieren.
Ein Beispiel ist JNDI:
JNDI bietet Schnittstellen und einige Klassen für die Kontextsuche. Die Standardmethode zum Nachschlagen eines Kontexts wird in IntialContext bereitgestellt. Diese Klasse verwendet intern SPI-Schnittstellen (unter Verwendung von NamingManager) für anbieterspezifische Implementierungen.
Weitere Informationen finden Sie in der folgenden JNDI-Architektur.
API steht für Application Programming Interface (Anwendungsprogrammierschnittstelle), wobei API ein Mittel für den Zugriff auf einen Dienst / eine Funktion ist, die von einer Software oder einer Plattform bereitgestellt wird.
SPI steht für Service Provider Interface (Service Provider-Schnittstelle), mit der SPI das Verhalten von Software oder einer Plattform einspeisen, erweitern oder ändern kann.
Die API ist normalerweise das Ziel für Clients, auf einen Dienst zuzugreifen, und verfügt über die folgenden Eigenschaften:
-> API ist eine programmatische Methode für den Zugriff auf einen Dienst, um ein bestimmtes Verhalten oder eine bestimmte Ausgabe zu erzielen
-> Aus Sicht der API-Evolution ist das Hinzufügen für Clients überhaupt kein Problem
-> Aber APIs, die einmal von Clients verwendet wurden, können (und sollten) nicht geändert / gelöscht werden, es sei denn, es gibt eine angemessene Kommunikation, da dies eine vollständige Verschlechterung der Client-Erwartungen darstellt
SPI hingegen richten sich an Anbieter und haben folgende Eigenschaften:
-> SPI ist eine Möglichkeit, das Verhalten einer Software oder Plattform zu erweitern / zu ändern (programmierbar vs. programmatisch).
-> Die SPI-Evolution unterscheidet sich von der API-Evolution, da das Entfernen von SPI kein Problem darstellt
-> Das Hinzufügen von SPI-Schnittstellen verursacht Probleme und kann vorhandene Implementierungen beschädigen
Weitere Erläuterungen finden Sie hier: Service Provider-Schnittstelle
NetBeans-FAQ: Was ist ein SPI? Wie unterscheidet es sich von einer API?
API ist ein allgemeiner Begriff - eine Abkürzung für Application Programming Interface - und bedeutet etwas (in Java normalerweise einige Java-Klassen), das eine Software verfügbar macht, wodurch andere Software mit ihr kommunizieren kann.
SPI steht für Service Provider Interface. Dies ist eine Teilmenge aller Dinge, die API-spezifisch für Situationen sein können, in denen eine Bibliothek Klassen bereitstellt, die von der Anwendung (oder API-Bibliothek) aufgerufen werden und die normalerweise die Aufgaben der Anwendung ändern.
Das klassische Beispiel ist JavaMail. Die API hat zwei Seiten:
- Die API-Seite - die Sie aufrufen, wenn Sie einen Mail-Client schreiben oder ein Postfach lesen möchten
- Die SPI-Seite, wenn Sie einen Wire-Protocol-Handler bereitstellen, mit dem JavaMail mit einem neuen Servertyp wie einem Nachrichten- oder IMAP-Server kommunizieren kann
Benutzer der API müssen die SPI-Klassen selten sehen oder mit ihnen sprechen und umgekehrt.
Wenn Sie in NetBeans den Begriff SPI sehen, handelt es sich normalerweise um Klassen, die ein Modul zur Laufzeit einfügen kann, damit NetBeans neue Aufgaben ausführen kann. Beispielsweise gibt es ein allgemeines SPI für die Implementierung von Versionskontrollsystemen. Verschiedene Module bieten Implementierungen dieses SPI für CVS-, Subversion-, Mercurial- und andere Revisionskontrollsysteme. Der Code, der sich mit Dateien befasst (die API-Seite), muss sich jedoch nicht darum kümmern, ob es ein Versionskontrollsystem gibt oder was es ist.
Es gibt einen Aspekt, der nicht besonders hervorgehoben zu werden scheint, aber sehr wichtig ist, um die Gründe für die Existenz der API / SPI-Aufteilung zu verstehen.
API / SPI-Split ist nur erforderlich, wenn sich die Plattform voraussichtlich weiterentwickeln wird. Wenn Sie eine API schreiben und "wissen" , dass keine zukünftigen Verbesserungen erforderlich sind, gibt es keine wirklichen Gründe, Ihren Code in zwei Teile aufzuteilen (außer ein sauberes Objektdesign zu erstellen).
Dies ist jedoch fast nie der Fall und die Menschen müssen die Freiheit haben, API zusammen mit zukünftigen Anforderungen weiterzuentwickeln - auf abwärtskompatible Weise.
Beachten Sie, dass bei all dem oben Gesagten davon ausgegangen wird, dass Sie eine Plattform erstellen, die von anderen Personen verwendet und / oder erweitert wird, und nicht Ihre eigene API, bei der Sie den gesamten Clientcode unter Kontrolle haben und somit nach Bedarf umgestalten können.
Zeigen wir es auf einem der bekannten Java-Objekte Collection
und Collections
.
API: Collections
ist eine Reihe statischer Dienstprogrammmethoden. Häufig werden Klassen, die API-Objekte darstellen, so definiert, dass final
sie (zur Kompilierungszeit) sicherstellen, dass kein Client dieses Objekt jemals "implementieren" kann , und sie können vom "Aufrufen" seiner statischen Methoden abhängen , z
Collections.emptySet();
Da alle Clients "aufrufen", aber nicht "implementieren" , können Autoren von JDK in der zukünftigen Version von JDK neue Methoden zum Collections
Objekt hinzufügen . Sie können sicher sein, dass es keinen Client brechen kann, selbst wenn es wahrscheinlich Millionen von Nutzungen gibt.
SPI: Collection
ist eine Schnittstelle, die impliziert, dass jeder seine eigene Version davon implementieren kann. Daher können Autoren von JDK keine neuen Methoden hinzufügen, da dies alle Clients beschädigen würde, die ihre eigene Collection
Implementierung geschrieben haben (*).
Wenn eine zusätzliche Methode hinzugefügt werden muss, muss normalerweise eine neue Schnittstelle erstellt werden, z. B. Collection2
die die frühere erweitert. Der SPI-Client kann dann entscheiden, ob auf die neue Version von SPI migriert und die zusätzliche Methode implementiert werden soll oder ob die ältere beibehalten werden soll.
Vielleicht haben Sie den Punkt bereits gesehen. Wenn Sie beide Teile zu einer Klasse zusammenfassen, wird Ihre API für alle Ergänzungen gesperrt. Dies ist auch der Grund, warum gute Java-APIs und Frameworks nicht verfügbar gemacht werden, abstract class
da sie ihre zukünftige Entwicklung in Bezug auf die Abwärtskompatibilität blockieren würden.
Wenn noch etwas unklar ist, empfehle ich zu überprüfen diese Seite der das oben Gesagte ausführlicher erläutert wird.
(*) Beachten Sie, dass dies nur bis Java 1.8 gilt, das das Konzept der default
in einer Schnittstelle definierten Methoden einführt .
Ich nehme an, ein SPI wird in ein größeres System eingebunden, indem bestimmte Funktionen einer API implementiert und sich dann über Service-Lookup-Mechanismen als verfügbar registriert werden. Eine API wird vom Endbenutzer-Anwendungscode direkt verwendet, kann jedoch SPI-Komponenten integrieren. Es ist der Unterschied zwischen Kapselung und direkter Verwendung.
Service Provider-Schnittstelle ist die Service-Schnittstelle, die alle Anbieter implementieren müssen. Wenn keine der vorhandenen Anbieterimplementierungen für Sie funktioniert, müssen Sie Ihren eigenen Dienstanbieter schreiben (Implementierung der Dienstschnittstelle) und sich irgendwo registrieren (siehe den nützlichen Beitrag von Roman).
Wenn Sie die vorhandene Anbieterimplementierung der Dienstschnittstelle wiederverwenden, verwenden Sie grundsätzlich die API dieses bestimmten Anbieters, die alle Methoden der Dienstschnittstelle sowie einige eigene öffentliche Methoden enthält. Wenn Sie Methoden der Anbieter-API außerhalb des SPI verwenden, verwenden Sie anbieterspezifische Funktionen.
In der Java-Welt sollen verschiedene Technologien modular und "steckbar" in einen Anwendungsserver sein. Es gibt dann einen Unterschied zwischen
Zwei Beispiele für solche Technologien sind JTA (Transaktionsmanager) und JCA (Adapter für JMS oder Datenbank). Aber es gibt noch andere.
Der Implementierer einer solchen steckbaren Technologie muss dann das SPI implementieren, um in der App steckbar zu sein. Server und stellen eine API bereit, die von der Endbenutzeranwendung verwendet werden soll. Ein Beispiel von JCA ist die ManagedConnection- Schnittstelle, die Teil des SPI ist, und die Verbindung , die Teil der Endbenutzer-API ist.