Java-tjenesteleverandørgrensesnitt

1. Oversikt

Java 6 har introdusert en funksjon for å oppdage og laste implementeringer som samsvarer med et gitt grensesnitt: Service Provider Interface (SPI).

I denne opplæringen vil vi introdusere komponentene i Java SPI og vise hvordan vi kan bruke den til en praktisk brukssak.

2. Vilkår og definisjoner av Java SPI

Java SPI definerer fire hovedkomponenter

2.1. Service

Et velkjent sett med programmeringsgrensesnitt og klasser som gir tilgang til noen spesifikk applikasjonsfunksjonalitet eller funksjon.

2.2. Tjenesteleverandørgrensesnitt

Et grensesnitt eller en abstrakt klasse som fungerer som en proxy eller et sluttpunkt for tjenesten.

Hvis tjenesten er ett grensesnitt, er det det samme som et tjenesteleverandørgrensesnitt.

Service og SPI sammen er velkjent i Java Ecosystem som API.

2.3. Tjenesteleverandør

En spesifikk implementering av SPI. Tjenesteleverandøren inneholder en eller flere konkrete klasser som implementerer eller utvider tjenestetypen.

En tjenesteleverandør konfigureres og identifiseres gjennom en leverandørkonfigurasjonsfil som vi legger i ressurskatalogen META-INF / tjenester. Filnavnet er det fullstendige navnet på SPI, og innholdet er det fullt kvalifiserte navnet på SPI-implementeringen.

Tjenesteleverandøren er installert i form av utvidelser, en jar-fil som vi plasserer i applikasjonens klassesti, Java-utvidelses klassestien eller den brukerdefinerte klassestien.

2.4. ServiceLoader

I hjertet av SPI er ServiceLoader klasse. Dette har rollen som å oppdage og laste implementeringer lat. Den bruker kontekstklassestien for å finne leverandørimplementeringer og plassere dem i en intern cache.

3. SPI-prøver i Java-økosystemet

Java gir mange SPIer. Her er noen eksempler på tjenesteleverandørgrensesnittet og tjenesten det gir:

  • CurrencyNameTilbyder: gir lokaliserte valutasymboler for Valuta klasse.
  • LocaleNameTilbyder: gir lokaliserte navn for Lokal klasse.
  • TimeZoneNameTilbyder: gir lokaliserte tidssone navn for Tidssone klasse.
  • DateFormatLeverandør: gir dato- og tidsformat for et spesifisert sted.
  • NumberFormatTilbyder: gir penge-, heltall- og prosentverdier for NumberFormat klasse.
  • Sjåfør: fra versjon 4.0 støtter JDBC API SPI-mønsteret. Eldre versjoner bruker Class.forName () metode for å laste drivere.
  • PersistenceTilbyder: gir implementering av JPA API.
  • JsonTilbyder: gir JSON-behandlingsobjekter.
  • JsonbTilbyder: gir JSON bindende objekter.
  • Utvidelse: gir utvidelser for CDI-containeren.
  • ConfigSourceProvider: gir en kilde for å hente konfigurasjonsegenskaper.

4. Fremvis: en valutakursapplikasjon

Nå som vi forstår det grunnleggende, la oss beskrive trinnene som kreves for å sette opp en valutakursapplikasjon.

For å markere disse trinnene, må vi bruke minst tre prosjekter: valutakurs-api, valutakurs-impl, og valutakurs-app.

I underavsnitt 4.1 vil vi dekke Service, den SPI og ServiceLoadergjennom modulen valutakurs-api, deretter i underavsnitt 4.2. vi implementerer vår service forsørger i valutakurs-impl modul, og til slutt vil vi bringe alt sammen i underavsnitt 4.3 gjennom modulen valutakurs-app.

Faktisk kan vi tilby så mange moduler som vi trenger for service forsørger og gjør dem tilgjengelige på kursstien til modulen valutakurs-app.

4.1. Bygg vår API

Vi starter med å lage et Maven-prosjekt kalt valutakurs-api. Det er god praksis at navnet ender med begrepet api, men vi kan kalle det uansett.

Deretter lager vi en modellklasse for å representere kursvalutaer:

pakke com.baeldung.rate.api; offentlig klasse Sitat {privat String valuta; privat LocalDate dato; ...}

Og så definerer vi vår Service for å hente tilbud ved å opprette grensesnittet Sitatstyrer:

pakke com.baeldung.rate.api offentlig grensesnitt QuoteManager {List getQuotes (String baseCurrency, LocalDate date); }

Deretter lager vi en SPI for vår tjeneste:

pakke com.baeldung.rate.spi; offentlig grensesnitt ExchangeRateProvider {QuoteManager create (); }

Og til slutt må vi lage en nytteklasse ExchangeRate.java som kan brukes av klientkoden. Denne klassen delegerer til ServiceLoader.

Først påkaller vi den statiske fabrikkmetoden laste() å få en forekomst av ServiceLoader:

ServiceLoader loader = ServiceLoader .load (ExchangeRateProvider.class); 

Og så påkaller vi repetere() metode for å søke og hente alle tilgjengelige implementeringer.

Iterator = loader.iterator (); 

Søkeresultatet er hurtigbufret slik at vi kan påberope oss ServiceLoader.reload () metode for å oppdage nylig installerte implementeringer:

Iterator = loader.reload (); 

Og her er vår nytteklasse:

offentlig klasse ExchangeRate {ServiceLoader loader = ServiceLoader .load (ExchangeRateProvider.class); offentlige Iterator-leverandører (boolsk oppdatering) {if (refresh) {loader.reload (); } retur loader.iterator (); }}

Nå som vi har en tjeneste for å få alle installerte implementeringer, kan vi bruke dem alle i klientkoden vår for å utvide applikasjonen vår eller bare en ved å velge en foretrukket implementering.

Merk at denne verktøyklassen ikke er pålagt å være en del av api prosjekt. Klientkode kan velge å påkalle ServiceLoader metoder seg selv.

4.2. Bygge tjenesteleverandøren

La oss nå lage et Maven-prosjekt som heter valutakurs-impl og vi legger til API-avhengighet til pom.xml:

 com.baeldung valutakurs-api 1.0.0-SNAPSHOT 

Deretter lager vi en klasse som implementerer SPI:

offentlig klasse YahooFinanceExchangeRateProvider implementerer ExchangeRateProvider {@Override public QuoteManager create () {return new YahooQuoteManagerImpl (); }}

Og her implementeringen av QuoteManager grensesnitt:

offentlig klasse YahooQuoteManagerImpl implementerer QuoteManager {@Override public List getQuotes (String baseCurrency, LocalDate date) {// henting fra Yahoo API}}

For å bli oppdaget oppretter vi en leverandørkonfigurasjonsfil:

META-INF / services / com.baeldung.rate.spi.ExchangeRateProvider 

Innholdet i filen er det fullt kvalifiserte klassenavnet til SPI-implementeringen:

com.baeldung.rate.impl.YahooFinanceExchangeRateProvider 

4.3. Sette det sammen

Til slutt, la oss lage et klientprosjekt som heter valutakurs-app og legg avhengighetsvalutakurs-api til klassestien:

 com.baeldung valutakurs-api 1.0.0-SNAPSHOT 

På dette tidspunktet kan vi ringe SPI fra søknaden vår:

ExchangeRate.providers (). ForEach (leverandør -> ...);

4.4. Kjører applikasjonen

La oss nå fokusere på å bygge alle modulene våre:

mvn ren pakke 

Så kjører vi søknaden vår med Java kommando uten å ta hensyn til leverandøren:

java -cp ./exchange-rate-api/target/exchange-rate-api-1.0.0-SNAPSHOT.jar :./exchange-rate-app/target/exchange-rate-app-1.0.0-SNAPSHOT.jar com.baeldung.rate.app.MainApp

Nå inkluderer vi leverandøren vår i java.ext.dirs utvidelse, og vi kjører applikasjonen igjen:

java -Djava.ext.dirs = $ JAVA_HOME / jre / lib / ext: ./ valutakurs-impl / mål: ./ valutakurs-impl / mål / avhenger -cp ./exchange-rate-api/target/ exchange-rate-api-1.0.0-SNAPSHOT.jar: ./ exchange-rate-app / target / exchange-rate-app-1.0.0-SNAPSHOT.jar com.baeldung.rate.app.MainApp 

Vi kan se at leverandøren vår er lastet.

5. Konklusjon

Nå som vi har utforsket Java SPI-mekanismen gjennom veldefinerte trinn, bør det være klart å se hvordan du bruker Java SPI for å lage moduler som er lett utvidbare eller utskiftbare.

Selv om eksemplet vårt brukte Yahoo-valutakurstjenesten for å vise kraften til å plugge inn i andre eksisterende eksterne API-er, trenger produksjonssystemer ikke å stole på tredjeparts-API-er for å lage gode SPI-applikasjoner.

Koden, som vanlig, finner du på Github.


$config[zx-auto] not found$config[zx-overlay] not found