Intro til vårfjernkontroll med HTTP-påkaller

1. Oversikt

I noen tilfeller må vi dekomponere et system i flere prosesser, som hver tar ansvar for et annet aspekt av applikasjonen vår. I disse scenariene er det ikke uvanlig at en av prosessene trenger for å synkronisere data fra en annen.

Spring Framework tilbyr en rekke verktøy som omfattende kalles Vårfjernkontroll som tillater oss å påkalle eksterne tjenester som om de, i det minste til en viss grad, var tilgjengelige lokalt.

I denne artikkelen vil vi sette opp en applikasjon basert på Spring’s HTTP påkaller, som utnytter naturlig Java-serialisering og HTTP for å gi ekstern metodeinnkalling mellom en klient og et serverprogram.

2. Servicedefinisjon

La oss anta at vi må implementere et system som lar brukerne bestille tur i en drosje.

La oss også anta at vi velger å bygge to forskjellige applikasjoner for å oppnå dette målet:

  • en bookingmotorsøknad for å sjekke om en drosjeforespørsel kan serveres, og
  • en front-end webapplikasjon som gjør det mulig for kunder å bestille turer, slik at tilgjengeligheten av en drosje er bekreftet

2.1. Service-grensesnitt

Når vi bruker Vårfjernkontroll med HTTP-påkaller, Vi må definere vår eksternt kallbare tjeneste gjennom et grensesnitt for å la Spring lage fullmakter på både klient- og serversiden som innkapsler det tekniske ved fjernsamtalen. Så la oss starte med grensesnittet til en tjeneste som lar oss bestille drosje:

offentlig grensesnitt CabBookingService {Booking bookRide (String pickUpLocation) kaster BookingException; }

Når tjenesten er i stand til å tildele en drosje, returnerer den en Bestilling objekt med en reservasjonskode. Bestilling må være serierbar fordi Spring's HTTP-innkaller må overføre forekomster fra serveren til klienten:

offentlig klasse Booking implementerer Serializable {private String bookingCode; @ Override public String toString () {returformat ("Ride bekreftet: kode '% s'.", BookingCode); } // standard getters / setters og en konstruktør}

Hvis tjenesten ikke kan bestille drosje, må en Booking unntak blir kastet. I dette tilfellet er det ikke nødvendig å merke klassen som Serialiserbar fordi Unntak implementerer det allerede:

offentlig klasse BookingException utvider unntak {public BookingException (strengmelding) {super (melding); }}

2.2. Emballasje av tjenesten

Tjenestegrensesnittet sammen med alle egendefinerte klasser som brukes som argumenter, returtyper og unntak, må være tilgjengelig både på klientens og serverens klassebane. En av de mest effektive måtene å gjøre det er å pakke dem alle i en .krukke fil som senere kan inkluderes som en avhengighet i serverens og klientens pom.xml.

La oss dermed sette all koden i en dedikert Maven-modul, kalt “api”; vi bruker følgende Maven-koordinater for dette eksemplet:

com.baeldung api 1.0-SNAPSHOT

3. Serverapplikasjon

La oss bygge bookingmotorapplikasjonen for å avsløre tjenesten ved hjelp av Spring Boot.

3.1. Maven avhengigheter

Først må du sørge for at prosjektet ditt bruker Spring Boot:

 org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE 

Du finner den siste Spring Boot-versjonen her. Vi trenger deretter Web-startmodulen:

 org.springframework.boot spring-boot-starter-web 

Og vi trenger tjenestedefinisjonsmodulen som vi samlet i forrige trinn:

 com.baeldung api 1.0-SNAPSHOT 

3.2. Tjenesteimplementering

Vi definerer først en klasse som implementerer tjenestens grensesnitt:

offentlig klasse CabBookingServiceImpl implementerer CabBookingService {@Override public Booking bookPickUp (String pickUpLocation) kaster BookingException {if (random () <0.3) throw new BookingException ("Cab unavailable"); returner ny booking (randomUUID (). toString ()); }}

La oss late som om dette er en sannsynlig implementering. Ved å bruke en test med en tilfeldig verdi kan vi reprodusere både vellykkede scenarier - når en tilgjengelig drosje er funnet og en reservasjonskode returnert - og sviktende scenarier - når en BookingException kastes for å indikere at det ikke er noen tilgjengelig drosje.

3.3. Å eksponere tjenesten

Vi må da definere en applikasjon med en bønne av typen HttpInvokerServiceExporter i konteksten. Det tar seg av å eksponere et HTTP-inngangspunkt i webapplikasjonen som senere blir påkalt av klienten:

@Configuration @ComponentScan @EnableAutoConfiguration public class Server {@Bean (name = "/ booking") HttpInvokerServiceExporter accountService () {HttpInvokerServiceExporter eksportør = ny HttpInvokerServiceExporter (); eksportør.setService (ny CabBookingServiceImpl ()); eksportør.setServiceInterface (CabBookingService.class); retur eksportør; } public static void main (String [] args) {SpringApplication.run (Server.class, args); }}

Det er verdt å merke seg at Spring’s HTTP påkaller bruker navnet på HttpInvokerServiceExporter bønne som en relativ bane for HTTP-endepunkt-URL.

Vi kan nå starte serverapplikasjonen og holde den i gang mens vi konfigurerer klientapplikasjonen.

4. Kundesøknad

La oss nå skrive klientapplikasjonen.

4.1. Maven avhengigheter

Vi bruker den samme tjenestedefinisjonen og den samme Spring Boot-versjonen som vi brukte på serversiden. Vi trenger fremdeles nettstarteravhengighet, men siden vi ikke trenger å starte en innebygd container automatisk, kan vi ekskludere Tomcat-starter fra avhengigheten:

 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat 

4.2. Klientimplementering

La oss implementere klienten:

@Configuration public class Client {@Bean public HttpInvokerProxyFactoryBean invoker () {HttpInvokerProxyFactoryBean invoker = new HttpInvokerProxyFactoryBean (); invoker.setServiceUrl ("// localhost: 8080 / booking"); invoker.setServiceInterface (CabBookingService.class); returinnkaller; } offentlig statisk ugyldig hoved (String [] args) kaster BookingException {CabBookingService service = SpringApplication .run (Client.class, args) .getBean (CabBookingService.class); out.println (service.bookRide ("13 Seagate Blvd, Key Largo, FL 33037")); }}

De @Bønne kommentert innkaller() metoden skaper en forekomst av HttpInvokerProxyFactoryBean. Vi må oppgi URL-en som den eksterne serveren reagerer på gjennom setServiceUrl () metode.

På samme måte som det vi gjorde for serveren, bør vi også tilby grensesnittet til tjenesten vi vil påberope oss eksternt gjennom setServiceInterface () metode.

HttpInvokerProxyFactoryBean implementerer vårens FactoryBean. EN FactoryBean er definert som en bønne, men Spring IoC-beholderen injiserer gjenstanden den lager, ikke selve fabrikken. Du kan finne mer informasjon om FactoryBean i vår fabrikkbønneartikkel.

De hoved() metoden bootstraps den frittstående applikasjonen og får en forekomst av CabBookingService fra sammenhengen. Under panseret er dette objektet bare en proxy opprettet av HttpInvokerProxyFactoryBean som tar seg av alle tekniske forhold som er involvert i utførelsen av fjernanropet. Takket være det kan vi nå enkelt bruke proxyen slik vi ville gjort hvis tjenesteimplementeringen hadde vært tilgjengelig lokalt.

La oss kjøre applikasjonen flere ganger for å utføre flere eksterne samtaler for å verifisere hvordan klienten oppfører seg når en drosje er tilgjengelig og når den ikke er.

5. Advarselstom

Når vi jobber med teknologier som tillater fjernanrop, er det noen fallgruver vi bør være godt klar over.

5.1. Vokt deg for unntak knyttet til nettverk

Vi bør alltid forvente det uventede når vi jobber med en upålitelig ressurs som nettverket.

La oss anta at klienten påkaller serveren mens den ikke kan nås - enten på grunn av et nettverksproblem eller fordi serveren er nede - så vil Spring Remoting øke en RemoteAccessException det er en RuntimeException.

Kompilatoren vil ikke tvinge oss til å inkludere påkallingen i en prøvefangstblokk, men vi bør alltid vurdere å gjøre det for å håndtere nettverksproblemer riktig.

5.2. Objekter overføres etter verdi, ikke etter referanse

Vårfjern fjern HTTP marshals metode argumenter og returnerte verdier for å overføre dem på nettverket. Dette betyr at serveren handler på en kopi av det angitte argumentet, og klienten handler på en kopi av resultatet opprettet av serveren.

Så vi kan for eksempel ikke forvente at å påkalle en metode på det resulterende objektet vil endre statusen til det samme objektet på serversiden fordi det ikke er noe delt objekt mellom klient og server.

5.3. Vokt deg for finkornede grensesnitt

Å påkalle en metode på tvers av nettverksgrensene er betydelig langsommere enn å påkalle den på et objekt i samme prosess.

Av denne grunn er det vanligvis god praksis å definere tjenester som skal påberopes eksternt med grovere kornede grensesnitt som er i stand til å fullføre forretningstransaksjoner som krever færre interaksjoner, selv på bekostning av et mer tungvint grensesnitt.

6. Konklusjon

Med dette eksemplet så vi hvordan det er enkelt med Spring Remoting å påkalle en ekstern prosess.

Løsningen er litt mindre åpen enn andre utbredte mekanismer som REST eller webtjenester, men i scenarier der alle komponentene er utviklet med Spring, kan den representere et levedyktig og langt raskere alternativ.

Som vanlig finner du kildene på GitHub.


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