Arbejde med Apache Thrift

1. Oversigt

I denne artikel vil vi opdage, hvordan vi udvikler platforme-klient-server applikationer ved hjælp af RPC framework kaldet Apache Thrift.

Vi vil dække:

  • Definition af datatyper og servicegrænseflader med IDL
  • Installation af biblioteket og generering af kilder til forskellige sprog
  • Implementering af de definerede grænseflader på et bestemt sprog
  • Implementering af klient / serversoftware

Hvis du vil gå direkte til eksempler, skal du gå direkte til afsnit 5.

2. Apache sparsommelighed

Apache Thrift blev oprindeligt udviklet af Facebook-udviklingsteamet og vedligeholdes i øjeblikket af Apache.

I sammenligning med protokolbuffere, der styrer platformsspecifikke objeksserialiserings- / deserialiseringsprocesser Thrift fokuserer primært på kommunikationslaget mellem komponenter i dit system.

Thrift bruger et specielt Interface Description Language (IDL) til at definere datatyper og servicegrænseflader, der er gemt som . sparsommelighed filer og bruges senere som input af compileren til generering af kildekoden til klient- og serversoftware, der kommunikerer over forskellige programmeringssprog.

For at bruge Apache Thrift i dit projekt skal du tilføje denne Maven-afhængighed:

 org.apache.thrift libthrift 0.10.0 

Du kan finde den nyeste version i Maven-arkivet.

3. Interface beskrivelsessprog

Som allerede beskrevet tillader IDL at definere kommunikationsgrænseflader på et neutralt sprog. Nedenfor finder du de aktuelt understøttede typer.

3.1. Basetyper

  • bool - en boolsk værdi (sand eller falsk)
  • byte - et 8-bit underskrevet heltal
  • i16 - et 16-bit underskrevet heltal
  • i32 - et 32-bit underskrevet heltal
  • i64 - et 64-bit underskrevet heltal
  • dobbelt - et 64-bit flydende nummer
  • snor - en tekststreng kodet ved hjælp af UTF-8-kodning

3.2. Særlige typer

  • binær - en sekvens af ukodede bytes
  • valgfri - en Java 8's Valgfri type

3.3. Structs

Sparsommelighed structs svarer til klasser i OOP-sprog, men uden arv. EN struct har et sæt stærkt indtastede felter, hver med et unikt navn som identifikator. Felter kan have forskellige kommentarer (numeriske felt-id'er, valgfri standardværdier osv.).

3.4. Beholdere

Genbrugsbeholdere er stærkt typede containere:

  • liste - en ordnet liste over elementer
  • sæt - et uordnet sæt unikke elementer
  • kort - et kort over strengt unikke nøgler til værdier

Containerelementer kan være af en hvilken som helst gyldig type.

3.5. Undtagelser

Undtagelser svarer funktionelt til structs, bortset fra at de arver fra de indfødte undtagelser.

3.6. Tjenester

Tjenester er faktisk kommunikationsgrænseflader defineret ved hjælp af sparsommelighedstyper. De består af et sæt navngivne funktioner, hver med en liste over parametre og en returtype.

4. Generering af kildekode

4.1. Sprogstøtte

Der er en lang liste over aktuelt understøttede sprog:

  • C ++
  • C #
  • Haskell
  • Java
  • Javascript
  • Node.js
  • Perl
  • PHP
  • Python
  • Rubin

Du kan tjekke den fulde liste her.

4.2. Brug af biblioteks eksekverbare fil

Download bare den nyeste version, bygg og installer den om nødvendigt, og brug følgende syntaks:

cd-sti / til / sparsommelighed -r --gen [SPROG] [FILENAME]

I ovenstående kommandoer, [SPROG] er et af de understøttede sprog og [FILNAVN] er en fil med IDL-definition.

Bemærk -r flag. Det fortæller Thrift at generere kode rekursivt, når den bemærker, at den er inkluderet i en given . sparsommelighed fil.

4.3. Brug af Maven Plugin

Tilføj pluginet i din pom.xml fil:

 org.apache.thrift.tools maven-sparsommelighed-plugin 0.1.11 sti / til / sparsommelighed sparsommelighedskilder genererer-kilder kompilerer 

Derefter skal du bare udføre følgende kommando:

mvn ren installation

Bemærk, at dette plugin ikke længere har nogen vedligeholdelse. Besøg denne side for mere information.

5. Eksempel på en klientserverapplikation

5.1. Definition af sparsommelsesfil

Lad os skrive nogle enkle tjenester med undtagelser og strukturer:

namespace cpp com.baeldung.thrift.impl namespace java com.baeldung.thrift.impl undtagelse InvalidOperationException {1: i32-kode, 2: strengbeskrivelse} struct CrossPlatformResource {1: i32 id, 2: strengnavn, 3: valgfri strenghilsen} tjeneste CrossPlatformService {CrossPlatformResource get (1: i32 id) kaster (1: InvalidOperationException e), ugyldig gemme (1: CrossPlatformResource ressource) kaster (1: InvalidOperationException e), liste getList () kaster (1: InvalidOperationException e), bool ) kaster (1: InvalidOperationException e)}

Som du kan se, er syntaksen ret enkel og selvforklarende. Vi definerer et sæt navneområder (pr. Implementeringssprog), en undtagelsestype, en struktur og endelig en serviceinterface, der deles på tværs af forskellige komponenter.

Derefter skal du bare gemme det som en service. sparsommelighed fil.

5.2. Kompilering og generering af en kode

Nu er det tid til at køre en compiler, der genererer koden for os:

sparsommelighed -r -out genereret --gen java /path/to/service.thrift

Som du måske ser, tilføjede vi et specielt flag -ud for at specificere outputmappen til genererede filer. Hvis du ikke fik nogen fejl, blev genereret bibliotek indeholder 3 filer:

  • CrossPlatformResource.java
  • CrossPlatformService.java
  • InvalidOperationException.java

Lad os generere en C ++ - version af tjenesten ved at køre:

sparsommelighed -r -out genereret --gen cpp /path/to/service.thrift

Nu får vi 2 forskellige gyldige implementeringer (Java og C ++) af den samme serviceinterface.

5.3. Tilføjelse af en serviceimplementering

Selvom Thrift har gjort det meste af arbejdet for os, er vi stadig nødt til at skrive vores egne implementeringer af CrossPlatformService. For at gøre det skal vi bare implementere en CrossPlatformService.Iface grænseflade:

offentlig klasse CrossPlatformServiceImpl implementerer CrossPlatformService.Iface {@Override public CrossPlatformResource get (int id) throw InvalidOperationException, TException {return new CrossPlatformResource (); } @ Override offentlig ugyldig gemme (CrossPlatformResource ressource) kaster InvalidOperationException, TException {saveResource (); } @ Override public List getList () kaster InvalidOperationException, TException {returner Collections.emptyList (); } @ Override offentlig boolsk ping () kaster InvalidOperationException, TException {return true; }}

5.4. Skrivning af en server

Som vi sagde, ønsker vi at opbygge en platform-klient-server-applikation, så vi har brug for en server til det. Det gode ved Apache Thrift er, at det har sin egen klient-server kommunikationsramme, der gør kommunikation til et stykke af kage:

offentlig klasse CrossPlatformServiceServer {offentlig ugyldig start () kaster TTransportException {TServerTransport serverTransport = ny TServerSocket (9090); server = ny TSimpleServer (ny TServer.Args (serverTransport) .processor (ny CrossPlatformService.Processor (ny CrossPlatformServiceImpl ()))); System.out.print ("Start af server ..."); server.serve (); System.out.println ("færdig."); } offentligt ugyldigt stop () {if (server! = null && server.isServing ()) {System.out.print ("Stop serveren ..."); server.stop (); System.out.println ("færdig."); }}} 

Første ting er at definere et transportlag med implementeringen af TServerTransport interface (eller abstrakt klasse, for at være mere præcis). Da vi taler om server, skal vi give en port til at lytte til. Så er vi nødt til at definere en TServer eksempel og vælg en af ​​de tilgængelige implementeringer:

  • TSimpleServer - til enkel server
  • TThreadPoolServer - til server med flere tråde
  • TNonblockingServer - til ikke-blokerende server med flere tråde

Og til sidst, lever en processorimplementering til den valgte server, som allerede blev genereret til os af Thrift, dvs. CrossPlatofformService.Processor klasse.

5.5. Skrivning af en klient

Og her er klientens implementering:

TTransport transport = ny TSocket ("localhost", 9090); transport.åbn (); TProtocol-protokol = ny TBinaryProtocol (transport); CrossPlatformService.Client-klient = ny CrossPlatformService.Client (protokol); boolsk resultat = client.ping (); transport.close ();

Fra et kundeperspektiv er handlingerne ret ens.

Først og fremmest definerer du transporten og retter den mod vores serverinstans, og vælg derefter den passende protokol. Den eneste forskel er, at her initialiserer vi klientinstansen, som endnu engang allerede blev genereret af Thrift, dvs. CrossPlatformService.Client klasse.

Da det er baseret på . sparsommelighed fildefinitioner kan vi direkte kalde metoder beskrevet der. I dette særlige eksempel client.ping () foretager et fjernopkald til serveren, som svarer med rigtigt.

6. Konklusion

I denne artikel har vi vist dig de grundlæggende begreber og trin i arbejdet med Apache Thrift, og vi har vist, hvordan du opretter et arbejdseksempel, der bruger Thrift-biblioteket.

Som normalt kan alle eksemplerne altid findes i GitHub-arkivet.