Java Service Provider Interface

1. Oversigt

Java 6 har introduceret en funktion til at opdage og indlæse implementeringer, der matcher en given grænseflade: Service Provider Interface (SPI).

I denne vejledning introducerer vi komponenterne i Java SPI og viser, hvordan vi kan anvende det til en praktisk brugssag.

2. Vilkår og definitioner af Java SPI

Java SPI definerer fire hovedkomponenter

2.1. Service

Et velkendt sæt programmeringsgrænseflader og klasser, der giver adgang til en bestemt applikationsfunktionalitet eller funktion.

2.2. Tjenesteudbyders interface

En grænseflade eller en abstrakt klasse, der fungerer som en proxy eller et slutpunkt til tjenesten.

Hvis tjenesten er en grænseflade, er den den samme som en tjenesteudbyders grænseflade.

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

2.3. Service udbyder

En specifik implementering af SPI. Tjenesteudbyderen indeholder en eller flere konkrete klasser, der implementerer eller udvider servicetypen.

En tjenesteudbyder konfigureres og identificeres gennem en udbyderkonfigurationsfil, som vi placerer i ressourcebiblioteket META-INF / tjenester. Filnavnet er det fuldt kvalificerede navn på SPI, og dets indhold er det fuldt kvalificerede navn på SPI-implementeringen.

Tjenesteudbyderen installeres i form af udvidelser, en jar-fil, som vi placerer i applikationens klassesti, Java-udvidelses klassestien eller den brugerdefinerede klassesti.

2.4. ServiceLoader

I hjertet af SPI er ServiceLoader klasse. Dette har den rolle at opdage og indlæse implementeringer doven. Det bruger kontekstklassestien til at finde udbyderimplementeringer og placere dem i en intern cache.

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

Java giver mange SPI'er. Her er nogle eksempler på tjenesteudbyderens grænseflade og den service, den leverer:

  • Valuta Navn Udbyder: giver lokaliserede valutasymboler til betalingsmiddel klasse.
  • LocaleName Provider: giver lokaliserede navne til Lokal klasse.
  • TimeZoneNameProvider: giver lokaliserede tidszonenavne til Tidszone klasse.
  • DateFormatTilbyder: indeholder dato- og tidsformater for et specificeret landestandard.
  • NumberFormatProvider: giver monetære, heltal og procentværdier for NumberFormat klasse.
  • Chauffør: fra version 4.0 understøtter JDBC API SPI-mønsteret. Ældre versioner bruger Class.forName () metode til at indlæse drivere.
  • Persistence Provider: leverer implementeringen af ​​JPA API.
  • JsonTilbyder: leverer JSON-behandlingsobjekter.
  • JsonbTilbyder: leverer JSON-bindende objekter.
  • Udvidelse: indeholder udvidelser til CDI-containeren.
  • ConfigSourceProvider: giver en kilde til at hente konfigurationsegenskaber.

4. Fremvisning: en anvendelse af valutakurser

Nu hvor vi forstår de grundlæggende, lad os beskrive de trin, der kræves for at oprette en valutakursapplikation.

For at fremhæve disse trin skal vi bruge mindst tre projekter: valutakurs-api, valutakursimpl, og valutakurs-app.

I underafsnit 4.1. Dækker vi Service, det SPI og ServiceLoadergennem modulet valutakurs-api, derefter i underafsnit 4.2. vi implementerer vores service udbyder i valutakurs-impl modul, og endelig bringer vi alt sammen i underafsnit 4.3 gennem modulet valutakurs-app.

Faktisk kan vi levere så mange moduler, som vi har brug for til service udbyder og gør dem tilgængelige på klassens sti i modulet valutakurs-app.

4.1. Opbygning af vores API

Vi starter med at oprette et Maven-projekt kaldet valutakurs-api. Det er god praksis, at navnet slutter med udtrykket api, men vi kan kalde det uanset.

Derefter opretter vi en modelklasse til repræsentation af kursvalutaer:

pakke com.baeldung.rate.api; offentlig klasse Citat {privat strengvaluta; privat LocalDate dato; ...}

Og så definerer vi vores Service for at hente tilbud ved at oprette grænsefladen CitatManager:

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

Dernæst opretter vi en SPI til vores service:

pakke com.baeldung.rate.spi; offentlig grænseflade ExchangeRateProvider {QuoteManager create (); }

Og endelig er vi nødt til at oprette en hjælpeklasse ExchangeRate.java der kan bruges af klientkode. Denne klasse delegerer til ServiceLoader.

For det første påberåber vi os den statiske fabriksmetode belastning() at få en forekomst af ServiceLoader:

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

Og så påberåber vi os iterate () metode til at søge og hente alle tilgængelige implementeringer.

Iterator = loader.iterator (); 

Søgeresultatet er cachelagret, så vi kan påberåbe sig ServiceLoader.reload () metode til at opdage nyinstallerede implementeringer:

Iterator = loader.reload (); 

Og her er vores forsyningsklasse:

offentlig klasse ExchangeRate {ServiceLoader loader = ServiceLoader .load (ExchangeRateProvider.class); offentlige Iterator-udbydere (boolsk opdatering) {if (refresh) {loader.reload (); } returner loader.iterator (); }}

Nu hvor vi har en tjeneste til at få alle installerede implementeringer, kan vi bruge dem alle i vores klientkode til at udvide vores applikation eller bare en ved at vælge en foretrukken implementering.

Bemærk, at dette værktøjsklasse ikke kræves for at være en del af api projekt. Klientkode kan vælge at påberåbe sig ServiceLoader metoder selv.

4.2. Opbygning af serviceudbyderen

Lad os nu oprette et Maven-projekt med navnet valutakurs-impl og vi tilføjer API-afhængighed til pom.xml:

 com.baeldung valutakurs-api 1.0.0-SNAPSHOT 

Derefter opretter vi en klasse, der implementerer vores SPI:

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

Og her er implementeringen af CitatManager grænseflade:

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

For at blive opdaget opretter vi en udbyderkonfigurationsfil:

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

Indholdet af filen er det fuldt kvalificerede klassenavn på SPI-implementeringen:

com.baeldung.rate.impl.YahooFinanceExchangeRateProvider 

4.3. At sætte det sammen

Lad os endelig oprette et klientprojekt kaldet valutakurs-app og tilføj afhængighedskursen-api til klassestien:

 com.baeldung valutakurs-api 1.0.0-SNAPSHOT 

På dette tidspunkt kan vi ringe til SPI fra vores ansøgning:

ExchangeRate.providers (). ForEach (udbyder -> ...);

4.4. Kørsel af applikationen

Lad os nu fokusere på at bygge alle vores moduler:

mvn ren pakke 

Derefter kører vi vores ansøgning med Java kommando uden at tage hensyn til udbyderen:

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

Nu inkluderer vi vores udbyder i java.ext.dirs udvidelse, og vi kører applikationen igen:

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

Vi kan se, at vores udbyder er indlæst.

5. Konklusion

Nu hvor vi har udforsket Java SPI-mekanismen gennem veldefinerede trin, bør det være klart at se, hvordan man bruger Java SPI til at oprette let udvidelige eller udskiftelige moduler.

Selvom vores eksempel brugte Yahoo-valutakurstjenesten til at vise styrken ved at tilslutte andre eksisterende eksterne API'er, behøver produktionssystemer ikke at stole på tredjeparts-API'er for at skabe gode SPI-applikationer.

Koden findes som sædvanlig på Github.


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