Microservices bouwen met Eclipse MicroProfile

1. Overzicht

In dit artikel zullen we ons concentreren op het bouwen van een microservice op basis van Eclipse MicroProfile.

We zullen bekijken hoe u een RESTful-webtoepassing kunt schrijven met behulp van JAX-RS-, CDI- en JSON-P-API's.

2. Een microservice-architectuur

Simpel gezegd, microservices zijn een softwarearchitectuurstijl die een compleet systeem vormt als een verzameling van verschillende onafhankelijke services.

Elk richt zich op één functionele perimeter en communiceert met de anderen via een taal-agnostisch protocol, zoals REST.

3. Eclipse MicroProfile

Eclipse MicroProfile is een initiatief dat tot doel heeft Enterprise Java te optimaliseren voor de Microservices-architectuur. Het is gebaseerd op een subset van Jakarta EE WebProfile API's, zodat we MicroProfile-applicaties kunnen bouwen zoals we Jakarta EE-applicaties bouwen.

Het doel van MicroProfile is om standaard-API's te definiëren voor het bouwen van microservices en het leveren van draagbare applicaties voor meerdere MicroProfile-runtimes.

4. Maven afhankelijkheden

Alle afhankelijkheden die nodig zijn om een ​​Eclipse MicroProfile-applicatie te bouwen, worden geleverd door deze BOM-afhankelijkheid (Bill Of Materials):

 org.eclipse.microprofile microprofile 1.2 pom meegeleverd 

De scope is ingesteld als voorzien omdat de MicroProfile-runtime al de API en de implementatie bevat.

5. Vertegenwoordigingsmodel

Laten we beginnen met het maken van een snelle resourceklasse:

openbare klasse Boek {privé String-id; private String naam; private String-auteur; privé Integer-pagina's; // ...}

Zoals we kunnen zien, is hier geen annotatie over Boek klasse.

6. CDI gebruiken

Simpel gezegd is CDI een API die afhankelijkheidsinjectie en levenscyclusbeheer biedt. Het vereenvoudigt het gebruik van Enterprise Beans in webapplicaties.

Laten we nu een door CDI beheerde bean maken als een winkel voor de boekweergave:

@ApplicationScoped openbare klasse BookManager {private ConcurrentMap inMemoryStore = nieuwe ConcurrentHashMap (); public String add (Book book) {// ...} public Book get (String id) {// ...} publieke lijst getAll () {// ...}} 

We annoteren deze klasse met @ApplicationScoped omdat we slechts één instantie nodig hebben waarvan de status door alle clients wordt gedeeld. Daarvoor hebben we een ConcurrentMap als een type-veilige gegevensopslag in het geheugen. Vervolgens hebben we methoden toegevoegd voor CRUD operaties.

Nu is onze boon klaar voor een CDI en kan hij in de boon worden geïnjecteerd BookEndpoint met de @Injecteren annotatie.

7. JAX-RS API

Om een ​​REST-applicatie met JAX-RS te maken, moeten we een Toepassing klasse geannoteerd met @ApplicationPath en een bron met annotaties @Pad.

7.1. JAX RS-applicatie

De JAX-RS-applicatie identificeert de basis-URI waaronder we de bron in een webapplicatie blootleggen.

Laten we de volgende JAX-RS-applicatie maken:

@ApplicationPath ("/ library") openbare klasse LibraryApplication breidt applicatie uit {}

In dit voorbeeld zijn alle JAX-RS-resourceklassen in de webtoepassing gekoppeld aan de BibliotheekApplication maken ze onder hetzelfde bibliotheek pad, dat is de waarde van de ApplicationPath-annotatie.

Deze geannoteerde klasse vertelt de JAX RS-runtime dat deze automatisch bronnen moet vinden en stelt deze bloot.

7.2. JAX RS-eindpunt

Een Eindpunt klasse, ook wel Bron class, zou één bron moeten definiëren, hoewel veel van dezelfde typen technisch mogelijk zijn.

Elke Java-klasse is geannoteerd met @Pad, of met ten minste één methode die is geannoteerd met @Path of @HttpMethod is een eindpunt.

Nu gaan we een JAX-RS-eindpunt maken dat die representatie blootlegt:

@Path ("books") @RequestScoped openbare klasse BookEndpoint {@Inject privé BookManager bookManager; @GET @Path ("{id}") @Produces (MediaType.APPLICATION_JSON) openbare reactie getBook (@PathParam ("id") String-id) {return Response.ok (bookManager.get (id)). Build (); } @GET @Produces (MediaType.APPLICATION_JSON) openbare reactie getAllBooks () {return Response.ok (bookManager.getAll ()). Build (); } @POST @Consumes (MediaType.APPLICATION_JSON) public Response add (Book book) {String bookId = bookManager.add (boek); return Response.created (UriBuilder.fromResource (this.getClass ()) .path (bookId) .build ()) .build (); }} 

Op dit punt hebben we toegang tot het BoekEindpunt Bron onder de / bibliotheek / boeken pad in de webapplicatie.

7.3. JAX RS JSON-mediatype

JAX RS ondersteunt vele mediatypen voor communicatie met REST-clients, maar Eclipse MicroProfile beperkt het gebruik van JSON aangezien het het gebruik van de JSOP-P API specificeert. Als zodanig moeten we onze methoden annoteren met @Consumes (MediaType.APPLICATION_JSON) en @Produceert (MediaType.APPLICATION_JSON).

De @Consumeert annotatie beperkt de geaccepteerde formaten - in dit voorbeeld wordt alleen het JSON-gegevensformaat geaccepteerd. De HTTP-verzoekheader Inhoudstype zou moeten zijn applicatie / json.

Hetzelfde idee schuilt achter de @Produceert annotatie. De JAX RS Runtime zou de respons naar het JSON-formaat moeten rangschikken. De HTTP-header van het verzoek Aanvaarden zou moeten zijn applicatie / json.

8. JSON-P

JAX RS Runtime ondersteunt JSON-P uit de doos, zodat we JsonObject als een methode-invoerparameter of als een retourtype.

Maar in de echte wereld werken we vaak met POJO-lessen. We hebben dus een manier nodig om de mapping tussen te maken JsonObject en POJO. Hier gaat de JAX RS-entiteitsprovider spelen.

Voor het rangschikken van JSON-invoerstroom naar het Boek POJO, dat is het aanroepen van een resourcemethode met een parameter van het type Boek, we moeten een klas maken BookMessageBodyReader:

@Provider @Consumes (MediaType.APPLICATION_JSON) public class BookMessageBodyReader implementeert MessageBodyReader {@Override public boolean isReadable (Class type, Type genericType, Annotation [] annotaties, MediaType mediaType) {return type.equals (Book.class); } @Override public Book readFrom (Class type, Type genericType, Annotation [] annotaties, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) gooit IOException, WebApplicationException {return BookMapper.map (entityStream); }} 

We doen hetzelfde proces om een Boek naar JSON-uitvoerstroom, dat is het aanroepen van een resourcemethode waarvan het retourtype is Boek, door een BoekMessageBodyWriter:

@Provider @Produces (MediaType.APPLICATION_JSON) public class BookMessageBodyWriter implementeert MessageBodyWriter {@Override public boolean isWriteable (Class type, Type genericType, Annotation [] annotaties, MediaType mediaType) {return type.equals (Book.class); } // ... @Override public void writeTo (Book book, Class type, Type genericType, Annotation [] annotaties, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) gooit IOException, WebApplicationException {JsonWriter jsonWriter = Json.createWriter (entityStream); JsonObject jsonObject = BookMapper.map (boek); jsonWriter.writeObject (jsonObject); jsonWriter.close (); }} 

Net zo BookMessageBodyReader en BookMessageBodyWriter zijn geannoteerd met @Provider, worden ze automatisch geregistreerd door de JAX RS-runtime.

9. Het bouwen en uitvoeren van de applicatie

Een MicroProfile-applicatie is draagbaar en zou in elke compatibele MicroProfile-runtime moeten draaien. We zullen uitleggen hoe we onze applicatie in Open Liberty kunnen bouwen en uitvoeren, maar we kunnen elke compatibele Eclipse MicroProfile gebruiken.

We configureren Open Liberty-runtime via een configuratiebestand server.xml:

  jaxrs-2.0 cdi-1.2 jsonp-1.0 

Laten we de plug-in toevoegen liberty-maven-plugin naar onze pom.xml:

  net.wasdev.wlp.maven.plugins liberty-maven-plugin 2.1.2 io.openliberty openliberty-runtime 17.0.0.4 zip $ {basedir} /src/main/liberty/config/server.xml $ {package.file} $ {packaging.type} false project / $ {project.artifactId} - $ {project.version} .war 9080 9443 install-server voorbereiden-pakket install-server create-server install-feature pakket-server-met-apps pakket installeren- apps pakket-server 

Deze plug-in is configureerbaar en gooit een reeks eigenschappen:

  bibliotheek $ {project.build.directory} / $ {app.name} -service.jar kan worden uitgevoerd 

Het bovenstaande doel levert een uitvoerbaar jar-bestand op, zodat onze applicatie een onafhankelijke microservice wordt die geïsoleerd kan worden geïmplementeerd en uitgevoerd. We kunnen het ook inzetten als Docker-image.

Voer de volgende opdracht uit om een ​​uitvoerbare jar te maken:

mvn-pakket 

En om onze microservice uit te voeren, gebruiken we deze opdracht:

java -jar doel / bibliotheek-service.jar

Hiermee wordt de Open Liberty-runtime gestart en wordt onze service geïmplementeerd. We hebben toegang tot ons eindpunt en krijgen alle boeken op deze URL:

curl // localhost: 9080 / bibliotheek / boeken

Het resultaat is een JSON:

[{"id": "0001-201802", "isbn": "1", "name": "Building Microservice With Eclipse MicroProfile", "author": "baeldung", "pages": 420}] 

Om één boek te krijgen, vragen we deze URL:

curl // localhost: 9080 / bibliotheek / boeken / 0001-201802

En het resultaat is JSON:

{"id": "0001-201802", "isbn": "1", "name": "Building Microservice With Eclipse MicroProfile", "author": "baeldung", "pages": 420}

Nu zullen we een nieuw boek toevoegen door te communiceren met de API:

curl -H "Content-Type: application / json" -X POST -d '{"isbn": "22", "name": "Gradle in Action", "author": "baeldung", "pages": 420 } '// localhost: 9080 / bibliotheek / boeken 

Zoals we kunnen zien, is de status van het antwoord 201, wat aangeeft dat het boek met succes is gemaakt, en de Plaats is de URI waarmee we er toegang toe hebben:

<HTTP / 1.1 201 Gemaakt <Locatie: // localhost: 9080 / library / books / 0009-201802

10. Conclusie

In dit artikel werd gedemonstreerd hoe je een eenvoudige microservice bouwt op basis van Eclipse MicroProfile, waarbij JAX RS, JSON-P en CDI worden besproken.

De code is beschikbaar op Github; dit is een op Maven gebaseerd project, dus het zou eenvoudig te importeren en uit te voeren moeten zijn zoals het is.