Création de microservices avec Eclipse MicroProfile

Création de microservices avec Eclipse MicroProfile

1. Vue d'ensemble

Dans cet article, nous nous concentrerons sur la création d'un microservice basé sur Eclipse MicroProfile.

Nous verrons comment écrire une application Web RESTful à l'aide des API JAX-RS, CDI et JSON-P.

2. Une architecture de microservice

En termes simples, les microservices sont un style d'architecture logicielle qui forme un système complet sous la forme d'une collection de plusieurs services indépendants.

Chacun se concentre sur un périmètre fonctionnel et communique avec les autres via un protocole indépendant de la langue, tel que REST.

3. MicroProfile Eclipse

Eclipse MicroProfile est une initiative qui vise à optimiser Enterprise Java pour l’architecture de Microservices. Il est basé sur un sous-ensemble d'API Java EE WebProfile, ce qui nous permet de créer des applications MicroProfile comme nous en construisons des Java EE.

L'objectif de MicroProfile est de définir des API standard pour la création de microservices et de fournir des applications portables sur plusieurs exécutions de MicroProfile.

4. Dépendances Maven

Toutes les dépendances requises pour créer une application Eclipse MicroProfile sont fournies par cette dépendance de nomenclature:


    org.eclipse.microprofile
    microprofile
    1.2
    pom
    provided

La portée est définie surprovided car le runtime MicroProfile inclut déjà l'API et l'implémentation.

5. Modèle de représentation

Commençons par créer une classe de ressources rapide:

public class Book {
    private String id;
    private String name;
    private String author;
    private Integer pages;
    // ...
}

Comme nous pouvons le voir, il n'y a pas d'annotation sur cette classeBook.

6. Utilisation de CDI

CDI est une API qui fournit l’injection de dépendances et la gestion du cycle de vie. Cela simplifie l'utilisation des beans entreprise dans les applications Web.

Créons maintenant un bean géré par CDI en tant que magasin pour la représentation du livre:

@ApplicationScoped
public class BookManager {

    private ConcurrentMap inMemoryStore
      = new ConcurrentHashMap<>();

    public String add(Book book) {
        // ...
    }

    public Book get(String id) {
        // ...
    }

    public List getAll() {
        // ...
    }
}

Nous annotons cette classe avec@ApplicationScoped car nous n'avons besoin que d'une seule instance dont l'état est partagé par tous les clients. Pour cela, nous avons utilisé unConcurrentMap comme magasin de données en mémoire de type sécurisé. Ensuite, nous avons ajouté des méthodes pour les opérationsCRUD.

Maintenant, notre bean est un CDI prêt et peut être injecté dans le beanBookEndpoint using l'annotation@Inject.

7. API JAX-RS

Pour créer une application REST avec JAX-RS, nous devons créer une classeApplication annotée avec@ApplicationPath et une ressource annotée avec@Path.

7.1. Application JAX RS

L'application JAX-RS identifie l'URI de base sous lequel nous exposons la ressource dans une application Web.

Créons l’application JAX-RS suivante:

@ApplicationPath("/library")
public class LibraryApplication extends Application {
}

Dans cet exemple, toutes les classes de ressources JAX-RS de l'application Web sont associées auxLibraryApplication, ce qui les place sous le même cheminlibrary, c'est-à-dire la valeur desApplicationPath annotation.

Cette classe annotée indique au moteur d'exécution JAX RS qu'elle doit rechercher les ressources automatiquement et les expose.

7.2. Point de terminaison JAX RS

Une classeEndpoint, également appelée classeResource, devrait définir une ressource bien que plusieurs des mêmes types soient techniquement possibles.

Chaque classe Java annotée avec@Path, ou ayant au moins une méthode annotée avec@Path or @HttpMethod est un point de terminaison.

Nous allons maintenant créer un point de terminaison JAX-RS qui expose cette représentation:

@Path("books")
@RequestScoped
public class BookEndpoint {

    @Inject
    private BookManager bookManager;

    @GET
    @Path("{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getBook(@PathParam("id") String id) {
        return Response.ok(bookManager.get(id)).build();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAllBooks() {
        return Response.ok(bookManager.getAll()).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response add(Book book) {
        String bookId = bookManager.add(book);
        return Response.created(
          UriBuilder.fromResource(this.getClass())
            .path(bookId).build())
            .build();
    }
}

À ce stade, nous pouvons accéder à la ressourceBookEndpoint sous le chemin/library/books dans l'application Web.

7.3. Type de support JAX RS JSON

JAX RS prend en charge de nombreux types de supports pour communiquer avec les clients REST, maisEclipse MicroProfile restricts the use of JSON car il spécifie l'utilisation de l'API JSOP-P. En tant que tel, nous devons annoter nos méthodes avec@Consumes(MediaType.APPLICATION_JSON) et @Produces(MediaType.APPLICATION_JSON).

L'annotation@Consumes limite les formats acceptés - dans cet exemple, seul le format de données JSON est accepté. L'en-tête de requête HTTPContent-Type doit êtreapplication/json.

La même idée se cache derrière l'annotation@Produces. Le Runtime JAX RS doit organiser la réponse au format JSON. L'en-tête HTTP de la requêteAccept doit êtreapplication/json.

8. JSON-P

JAX RS Runtime prend en charge JSON-P prêt à l'emploi afin que nous puissions utiliserJsonObject comme paramètre d'entrée de méthode ou type de retour.

Mais dans le monde réel, nous travaillons souvent avec des classes POJO. Nous avons donc besoin d'un moyen de faire le mappage entreJsonObject et POJO. Voici où le fournisseur d'entités JAX RS va jouer.

Pour marshaler le flux d'entrée JSON vers le POJOBook, cela appelle une méthode de ressource avec un paramètre de typeBook,, nous devons créer une classeBookMessageBodyReader:

@Provider
@Consumes(MediaType.APPLICATION_JSON)
public class BookMessageBodyReader implements MessageBodyReader {

    @Override
    public boolean isReadable(
      Class type, Type genericType,
      Annotation[] annotations,
      MediaType mediaType) {

        return type.equals(Book.class);
    }

    @Override
    public Book readFrom(
      Class type, Type genericType,
      Annotation[] annotations,
      MediaType mediaType,
      MultivaluedMap httpHeaders,
      InputStream entityStream) throws IOException, WebApplicationException {

        return BookMapper.map(entityStream);
    }
}

Nous effectuons le même processus pour démarseler un flux de sortieBook vers JSON, c'est-à-dire en appelant une méthode de ressource dont le type de retour estBook, en créant unBookMessageBodyWriter:

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class BookMessageBodyWriter
  implements MessageBodyWriter {

    @Override
    public boolean isWriteable(
      Class type, Type genericType,
      Annotation[] annotations,
      MediaType mediaType) {

        return type.equals(Book.class);
    }

    // ...

    @Override
    public void writeTo(
      Book book, Class type,
      Type genericType,
      Annotation[] annotations,
      MediaType mediaType,
      MultivaluedMap httpHeaders,
      OutputStream entityStream) throws IOException, WebApplicationException {

        JsonWriter jsonWriter = Json.createWriter(entityStream);
        JsonObject jsonObject = BookMapper.map(book);
        jsonWriter.writeObject(jsonObject);
        jsonWriter.close();
    }
}

CommeBookMessageBodyReader etBookMessageBodyWriter sont annotés avec@Provider, ils sont automatiquement enregistrés par le moteur d'exécution JAX RS.

9. Création et exécution de l'application

Une application MicroProfile est portable et doit s'exécuter dans n'importe quel environnement d'exécution MicroProfile conforme. Nous allons expliquer comment créer et exécuter notre application dansOpen Liberty, mais nous pouvons utiliser n'importe quel MicroProfile Eclipse conforme.

Nous configurons le runtime Open Liberty via un fichier de configurationserver.xml:


    
        jaxrs-2.0
        cdi-1.2
        jsonp-1.0
    
    
    
    

Ajoutons le pluginliberty-maven-plugin à notre 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
            prepare-package
            
                install-server
                create-server
                install-feature
            
        
        
            package-server-with-apps
            package
            
                install-apps
                package-server
            
        
    

Ce plugin est configurable avec un ensemble de propriétés:


    
    library
    ${project.build.directory}/${app.name}-service.jar
    runnable

L'objectif exec ci-dessus génère un fichier jar exécutable, de sorte que notre application constitue un microservice indépendant pouvant être déployé et exécuté de manière isolée. Nous pouvons également le déployer en tant qu'image Docker.

Pour créer un fichier jar exécutable, exécutez la commande suivante:

mvn package

Et pour exécuter notre microservice, nous utilisons cette commande:

java -jar target/library-service.jar

Cela démarrera le runtime Open Liberty et déploiera notre service. Nous pouvons accéder à notre point de terminaison et obtenir tous les livres à cette adresse URL:

curl http://localhost:9080/library/books

Le résultat est un JSON:

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

Pour obtenir un seul livre, nous demandons cette URL:

curl http://localhost:9080/library/books/0001-201802

Et le résultat est JSON:

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

Nous allons maintenant ajouter un nouveau livre en interagissant avec l'API:

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

Comme nous pouvons le voir, le statut de la réponse est 201, indiquant que le livre a été créé avec succès, et leLocation est l'URI par lequel nous pouvons y accéder:

< HTTP/1.1 201 Created
< Location: http://localhost:9080/library/books/0009-201802

10. Conclusion

Cet article a montré comment créer un microservice simple basé sur Eclipse MicroProfile et traitant de JAX RS, JSON-P et CDI.

Le code est disponibleover on Github; il s'agit d'un projet basé sur Maven, il devrait donc être simple à importer et à exécuter tel quel.