Różnica między SPI a API?

Odpowiedzi:

394
  • API to opis klas / interfejsów / metod / ... które wywołujesz i których używasz do osiągnięcia celu, oraz
  • SPI to opis klas / interfejsów / metod / ..., które rozszerzasz i wdrażasz, aby osiągnąć cel.

Innymi słowy, API mówi ci, co konkretna klasa / metoda robi dla ciebie, a SPI mówi, co musisz zrobić, aby się dostosować.

Zwykle API i SPI są osobne. Na przykład, w JDBC klasa jest częścią SPI: Jeśli po prostu chcesz używać JDBC, nie trzeba go używać bezpośrednio, ale każdy, kto realizuje sterownik JDBC musi implementować tej klasy.Driver

Czasami jednak się pokrywają. Interfejs jest zarówno SPI i API go używać rutynowo podczas korzystania ze sterownika JDBC i musi być realizowany przez dewelopera sterownika JDBC.Connection

Joachim Sauer
źródło
brzmi dobrze. po prostu linie między interfejsem SPI i interfejsem API mogą być nieco szare, ponieważ większość interfejsów API ma abstrakcyjne klasy / interfejsy, które użytkownik może zaimplementować, aby załatwić sprawy również ...
kctang
1
@koss: większość API? Wiem, co masz na myśli, ale nie widzę tych rzeczy zbyt często.
Joachim Sauer
2
Interfejs API jest bardziej odpowiedni dla programistów, a SPI dla dostawców.
Azfar Niaz,
7
@AzfarNiaz: cóż, ponieważ dostawcy zatrudniają programistów do tworzenia swoich produktów, oba są istotne dla programistów ;-)
Joachim Sauer
Czy w Javie adnotacje są częścią SPI? Na przykład, jeśli muszę dodać @SomeAnnotationdo swojej klasy, aby została podniesiona przez jakiś framework, czy ta klasa adnotacji SomeAnnotation.classbyłaby uważana za część SPI, nawet jeśli technicznie jej nie rozszerzam ani nie implementuję?
Adam Burley,
59

From Effective Java, 2nd Edition :

Struktura dostawcy usług to system, w którym wielu dostawców usług wdraża usługę, a system udostępnia implementacje swoim klientom, oddzielając je od implementacji.

Istnieją trzy podstawowe elementy struktury dostawcy usług: interfejs usługi, który dostawcy wdrażają; interfejs API rejestracji dostawcy, którego system używa do rejestrowania implementacji, umożliwiając klientom dostęp do nich; oraz interfejs API dostępu do usługi, którego klienci używają do uzyskania wystąpienia usługi. Interfejs API dostępu do usługi zazwyczaj pozwala, ale nie wymaga od klienta określenia pewnych kryteriów wyboru dostawcy. W przypadku braku takiej specyfikacji interfejs API zwraca instancję domyślnej implementacji. Interfejs API dostępu do usług to „elastyczna fabryka statyczna”, która stanowi podstawę struktury usługodawcy.

Opcjonalnym czwartym komponentem struktury dostawcy usług jest interfejs dostawcy usług, który dostawcy implementują w celu tworzenia instancji ich implementacji usług. W przypadku braku interfejsu usługodawcy implementacje są rejestrowane według nazwy klasy i tworzone w sposób refleksyjny (pozycja 53). W przypadku JDBC połączenie odgrywa rolę interfejsu usługi, DriverManager.registerDriver to interfejs API rejestracji dostawcy, DriverManager.getConnection to interfejs API dostępu do usługi, a Driver to interfejs dostawcy usług.

Istnieje wiele wariantów wzorca struktury usługodawcy. Na przykład interfejs API dostępu do usługi może zwrócić bogatszy interfejs usługi niż ten wymagany przez dostawcę, przy użyciu wzorca adaptera [Gamma95, str. 139]. Oto prosta implementacja z interfejsem dostawcy usług i domyślnym dostawcą:

// 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();
    }
}
rzymski
źródło
3
dzięki za bardzo ładny opis na platformie usługodawcy. to będzie przydatne wiedzieć. jednak nie opisuje jasno „różnicy” między api & spi, więc nie będę tutaj zaznaczać ... ;-)
kctang
23

Różnica między interfejsem API a interfejsem SPI pojawia się, gdy interfejs API dodatkowo zapewnia pewne konkretne implementacje. W takim przypadku dostawca usług musi zaimplementować kilka interfejsów API (zwanych SPI)

Przykładem jest JNDI:

JNDI zapewnia interfejsy i niektóre klasy do wyszukiwania kontekstowego. Domyślny sposób wyszukiwania kontekstu jest dostępny w IntialContext. Ta klasa wewnętrznie będzie używać interfejsów SPI (przy użyciu NamingManager) do implementacji specyficznych dla dostawcy.

Zobacz poniżej architekturę JNDI dla lepszego zrozumienia.

Wpisz opis zdjęcia tutaj

Sandeep Jindal
źródło
22

API oznacza Application Programming Interface, gdzie API jest środkiem dostępu do usługi / funkcji zapewnianej przez oprogramowanie lub platformę.

SPI oznacza Service Provider Interface, gdzie SPI jest sposobem na wstrzyknięcie, rozszerzenie lub zmianę zachowania oprogramowania lub platformy.

Interfejs API jest zwykle docelowy dla klientów w celu uzyskania dostępu do usługi i ma następujące właściwości:

-> API to programowy sposób uzyskiwania dostępu do usługi w celu osiągnięcia określonego zachowania lub wyniku

-> Z punktu widzenia ewolucji API dodawanie nie stanowi żadnego problemu dla klientów

-> Ale API raz używane przez klientów nie może (i nie powinno) być zmieniane / usuwane, chyba że istnieje odpowiednia komunikacja, ponieważ jest to całkowite pogorszenie oczekiwań klienta

Z drugiej strony SPI są skierowane do dostawców i mają następujące właściwości:

-> SPI to sposób na rozszerzenie / zmianę zachowania oprogramowania lub platformy (programowalny vs. programowy)

-> Ewolucja SPI różni się od ewolucji API, w usuwaniu SPI nie ma problemu

-> Dodanie interfejsów SPI spowoduje problemy i może przerwać istniejące implementacje

Aby uzyskać więcej wyjaśnień, kliknij tutaj: Interfejs usługodawcy

Venkata Aditya Pavan
źródło
12

FAQ NetBeans: Co to jest SPI? Czym różni się od interfejsu API?

API jest terminem ogólnym - akronimem interfejsu programowania aplikacji - oznacza coś (w Javie, zwykle niektóre klasy Java), na które narażone jest oprogramowanie, które pozwala innym programom na komunikację z nim.

SPI to skrót od Service Provider Interface. Jest to podzbiór wszystkich rzeczy, które mogą być specyficzne dla interfejsu API w sytuacjach, w których biblioteka udostępnia klasy wywoływane przez aplikację (lub bibliotekę API) i które zwykle zmieniają możliwości aplikacji.

Klasycznym przykładem jest JavaMail. Jego interfejs API ma dwie strony:

  • Strona API - do której dzwonisz, jeśli piszesz klienta poczty lub chcesz przeczytać skrzynkę pocztową
  • Strona SPI, jeśli udostępniasz moduł obsługi protokołu przewodowego, który umożliwia JavaMailowi ​​komunikowanie się z nowym rodzajem serwera, takim jak serwer wiadomości lub serwer IMAP

Użytkownicy interfejsu API rzadko muszą zobaczyć klasy SPI lub porozmawiać z nimi i na odwrót.

W NetBeans, gdy widzisz termin SPI, zwykle mówi się o klasach, które moduł może wstrzykiwać w czasie wykonywania, które pozwalają NetBeans robić nowe rzeczy. Na przykład istnieje ogólny SPI do wdrażania systemów kontroli wersji. Różne moduły zapewniają implementacje tego SPI dla CVS, Subversion, Mercurial i innych systemów kontroli wersji. Jednak kod zajmujący się plikami (po stronie API) nie musi dbać o to, czy istnieje system kontroli wersji, czy co to jest.

Ondra Žižka
źródło
5

Jest jeden aspekt, który nie wydaje się być zbytnio podkreślany, ale jest bardzo ważny, aby zrozumieć powody istnienia podziału API / SPI.

Podział API / SPI jest wymagany tylko wtedy, gdy oczekuje się ewolucji platformy. Jeśli napiszesz interfejs API i „wiesz”, że nie będzie on wymagał żadnych przyszłych ulepszeń, nie ma prawdziwych powodów, aby podzielić kod na dwie części (oprócz stworzenia czystego projektu obiektu).

Ale prawie nigdy tak nie jest i ludzie muszą mieć swobodę ewolucji API wraz z przyszłymi wymaganiami - w sposób kompatybilny wstecz.

Zauważ, że wszystkie powyższe założenia zakładają, że budujesz platformę, z której korzystają inni użytkownicy i / lub je rozbudowujesz, a nie własny interfejs API, w którym masz cały kod klienta pod kontrolą, a zatem możesz go refaktoryzować w dowolny sposób.

Pokażmy to na jednym ze znanych obiektów Java Collectioni Collections.


API: Collections to zestaw statycznych metod narzędziowych. Często klasy reprezentujące obiekt API są definiowane, ponieważ finalzapewniają (w czasie kompilacji), że żaden klient nigdy nie może „zaimplementować” tego obiektu i mogą polegać na „wywołaniu” jego metod statycznych, np.

Collections.emptySet();

Ponieważ wszyscy klienci „dzwonią”, ale nie „implementują” , autorzy JDK mogą dodawać nowe metody do Collectionsobiektu w przyszłej wersji JDK. Mogą być pewni, że nie złamie żadnego klienta, nawet jeśli prawdopodobnie istnieją miliony zastosowań.


SPI: Collection jest interfejsem, który sugeruje, że każdy może zaimplementować swoją własną wersję. Dlatego autorzy JDK nie mogą dodawać do niego nowych metod, ponieważ spowodowałoby to uszkodzenie wszystkich klientów, którzy napisali własną Collectionimplementację (*).

Zazwyczaj, gdy wymagana jest dodatkowa metoda, należy utworzyć nowy interfejs, np. Collection2Rozszerzający poprzednią. Klient SPI może następnie zdecydować, czy przeprowadzić migrację do nowej wersji SPI i wdrożyć dodatkową metodę, czy też trzymać się starszej.


Być może już widziałeś sens. Jeśli połączysz oba elementy razem w jedną klasę, interfejs API zostanie zablokowany przed wszelkimi dodatkami. To jest również powód, dla którego dobre interfejsy API i platformy Java nie ujawniają się, abstract classponieważ blokowałyby ich przyszłą ewolucję pod względem kompatybilności wstecznej.

Jeśli coś jest nadal niejasne, polecam sprawdzić tę stronę, która wyjaśnia to bardziej szczegółowo.


(*) Zauważ, że jest to prawdą tylko do Java 1.8, która wprowadza koncepcję defaultmetod zdefiniowanych w interfejsie.

Martin Janíček
źródło
4

Przypuszczam, że sloty SPI w większym systemie są implementowane przez niektóre funkcje API, a następnie rejestrują się jako dostępne za pośrednictwem mechanizmów wyszukiwania usług. Interfejs API jest używany bezpośrednio przez kod aplikacji użytkownika końcowego, ale może integrować komponenty SPI. To różnica między enkapsulacją a bezpośrednim użyciem.

Chris Dennett
źródło
dzięki za odpowiedź Chris. jakieś przykłady istniejących bibliotek Java (tj. Servlet, JDBC itp.)? ... jak to czyni je API / SPI. trudno jest wyobrazić sobie różnicę na podstawie samego opisu.
kctang
1
Interfejs API to JDBC, SPI dla JDBC to interfejs konektora bazy danych, którego programiści SPI mogą używać do tworzenia nowych konektorów bazy danych, które programista może wybrać do użycia.
Chris Dennett
4

Interfejs usługodawcy to interfejs usług, który wszyscy dostawcy muszą wdrożyć. Jeśli żadna z istniejących implementacji dostawcy nie działa dla Ciebie, musisz napisać własnego usługodawcę (implementując interfejs usługi) i gdzieś się zarejestrować (zobacz przydatny post Roman).

Jeśli ponownie wykorzystujesz istniejącą implementację interfejsu usługi dla dostawcy, w zasadzie używasz interfejsu API tego konkretnego dostawcy, który obejmuje wszystkie metody interfejsu usługi oraz kilka własnych metod publicznych. Jeśli używasz metod interfejsu API dostawcy poza interfejsem SPI, korzystasz z funkcji specyficznych dla dostawcy.

tapasvi
źródło
2

W świecie Java różne technologie mają być modułowe i „podłączane” do serwera aplikacji. Jest wtedy różnica między

  • serwer aplikacji
    • [SPI]
  • technologia wtykowa
    • [API]
  • aplikacja użytkownika końcowego

Dwa przykłady takich technologii to JTA (menedżer transakcji) i JCA (adapter do JMS lub bazy danych). Ale są też inni.

Wdrożenie takiej technologii wtykowej musi następnie zaimplementować interfejs SPI, aby można ją było podłączyć w aplikacji. serwer i zapewnić interfejs API do użycia przez aplikację użytkownika końcowego. Przykładem JCA jest interfejs ManagedConnection , który jest częścią SPI, i połączenie, które jest częścią interfejsu API użytkownika końcowego.

ewernli
źródło