Débutant Intermédiaire

Faites des microservices Java EE avec Wildfly-swarm

swarm_logo_finalLa tendance de l’année 2016 est définitivement celle des microservices. Ce style d’architecture en mode distribué, utilisé aujourd’hui par Netflix, eBay ou encore Amazon, connaît un fort succès auprès des entreprises IT et ne cesse de faire des émules. L’engouement est tel que Red Hat, accompagné de partenaires comme IBM, Tomitribe, Payara et London Java Community, annonce à la conférence DevNation une initiative autour des microservices Java EE appelée : MicroProfile.

Ce projet, qui n’en est qu’au stade embryonnaire, souhaite établir une plateforme commune en rassemblant des technologies standards que la plupart des développeurs connaissent déjà comme JAX-RS, JPA, CDI, JSON-P afin de privilégier la réutilisabilité des connaissances et l’interopérabilité des composants.

La première version de la plateforme sortira en Septembre avec l’aide de la communauté et de Red Hat qui propose déjà une implémentation de référence basée sur Wildfly-Swarm.

Qu’est-ce que Wildfly-swarm ?

swarm-uberjarWildfly-Swarm permet de packager des applications Java EE avec les dépendances minimums sous la forme d’un jar exécutable que l’on appelle un UberJar ou “fat-jar”. Celui-ci est déployable grâce à un conteneur embarqué dérivé de Wildfly mais en version minimaliste. Ainsi, chaque fat-jar généré est un microservice léger et déployable, capable d’être scalé de façon indépendante et ne comportant que le nécessaire, comme on peut le voir dans le schéma ci-contre.

Pour utiliser Wildfly-Swarm, il suffit simplement de rajouter, dans le pom.xml de votre projet, le plugin maven suivant :

<build>
  <plugins>
    <plugin>
      <groupId>org.wildfly.swarm</groupId>
      <artifactId>wildfly-swarm-plugin</artifactId>
      <executions>
        <execution>
          <goals>
            <goal>package</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Wildfly

Le serveur Wildfly étant au coeur des concepts inhérents à Wildfly-Swarm, il est important de comprendre comment il fonctionne. Wildfly est un serveur d’applications écrit en Java qui vient tout juste de sortir en version 10 finale. Il était anciennement appelé JBoss Application Server et est édité par la société Red Hat.

L’architecture de Wildfly est basée sur la notion de “sous-systèmes” que l’on peut ajouter ou enlever selon ses besoins. Cela permet d’enlever les fonctionnalités inutiles et ainsi réduire la taille et diminuer la consommation mémoire du serveur.

Un sous-système est un ensemble d’extensions permettant d’étendre le serveur Wildlfy :

 <extensions>
    <extension module="org.jboss.as.transactions"/>
    <extension module="org.jboss.as.webservices" />
    <extension module="org.jboss.as.weld" />
</extensions>

Une extension peut fournir des features comme la gestion de servlet, un conteneur EJB, ou JTA, ce qui rend Wildfly facilement configurable. Par exemple, si l’on souhaite avoir comme extension la gestion de servlet, il suffit de ne laisser que l’extension associée. Ainsi, la version Servlet-Only Distribution ne pèse que 28Mo.

BOM (Bill Of Material)

Le BOM est une notion introduite par MAVEN et qui existe depuis 2008, mais n’est pas spécifiquement liée à Wildfly. Malgré l’ancienneté de cette feature, elle reste encore assez peu utilisée et surtout peu connue.
Qu’est-ce qu’un BOM ? Pour résumer, c’est simplement un pom qui va définir les versions des artéfacts, de façon consistante, dans la section dependencyManagement. L’avantage d’un BOM est donc de pouvoir s’assurer de la cohérence des librairies de la stack avec la version que l’on aura spécifiée.

Exemple d’un BOM :

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.test</groupId>
      <artifactId>bom</artifactId>
      <version>1.0.0</version>
      <packaging>pom</packaging>
      <properties>
        <project1Version>1.0.0</project1Version>
        <project2Version>1.0.0</project2Version>
      </properties>
      <dependencyManagement>
        <dependencies>
          <dependency>
            <groupId>com.test</groupId>
            <artifactId>project1</artifactId>
            <version>${project1Version}</version>
          </dependency>
          <dependency>
            <groupId>com.test</groupId>
            <artifactId>project2</artifactId>
            <version>${project1Version}</version>
          </dependency>
        </dependencies>
      </dependencyManagement>
      <modules>
        <module>parent</module>
      </modules>
    </project>

Exemple d’utilisation du BOM :

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.wildfly.swarm</groupId>
        <artifactId>bom</artifactId>
        <version>${version.wildfly.swarm}</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>

Dans l’exemple ci-dessus, le BOM sera déclaré au niveau de la section dependencyManagement du pom parent dans le cadre d’un projet maven multi-modules. Ainsi, les modules enfants pourront importer les artéfacts dont ils auront besoin sans avoir à déclarer à chaque fois la version. Dans le cas de Wildfly-Swarm, on appelle ces artéfacts des “Fractions”.

Les Fractions

On appelle “Fractions” les différents modules qui composent Wildfly-Swarm. La plupart des Fractions proviennent des sous-systèmes de Widlfy mais certains peuvent apporter des fonctionnalités externes à Wildfly, telles que Jolokia ou Ribbon de NetFlix.
Ci-dessous, un exemple de Fraction qui permet d’ajouter le support de JPA dans une application.

<dependency>
  <groupId>org.wildfly.swarm</groupId>
  <artifactId>jpa</artifactId>
</dependency>

En voici une liste exhaustive :

batch-jberet=javax.batch
bean-validation=javax.validation*
cdi=javax.inject,javax.enterprise.inject,javax.enterprise.context,javax.enterprise.event
ejb=javax.ejb
ejb-remote=javax.ejb:Remote
infinispan=org.infinispan
javafx=javafx*
jaxrs=javax.ws.rs
jaxrs-cdi=javax.ws.rs+javax.inject
jaxrs-jaxb=javax.ws.rs+javax.xml.bind*
jaxrs-jsonp=javax.ws.rs+javax.json
jpa=javax.persistence
jsf=javax.faces*
mail=javax.mail
messaging=javax.jms
spring=org.springframework*
swagger=io.swagger.annotations
transactions=javax.transaction
undertow=javax.servlet
webservices=javax.jws

UberJar

Le concept d’UberJar existait bien avant que Wildfly-Swarm ne l’utilise. A la base, un UberJar est une archive jar exécutable comportant plusieurs librairies. Dans le cas de Wildfly-Swarm, le concept est bien sûr le même, c’est une archive contenant l’application métier avec les dépendances nécessaires mais avec un conteneur dérivé de Wildfly, ce qui rend le jar déployable.

Comment déployer une application Wildfly-swarm?

Avant de démarrer une application Wildfly-Swarm, il faut la rendre exécutable. Le conteneur étant au coeur des applications Wildfly-Swarm, une api est fournie afin d’instancier, de démarrer et d’arrêter le conteneur Swarm embarqué. Il est possible de le démarrer dans un point d’entrée Main ou, le cas échéant, par un Main fourni par Wildfly : org.wildfly.swarm.Swarm#main(…) qui gère automatiquement la construction et le déploiement du conteneur.

public class MyMain {
    public static void main(String...args) {

        // Instantiate the container
        Swarm container = new Swarm();

        // Create one or more deployments
        JAXRSArchive deployment = ShrinkWrap.create(JAXRSArchive.class);
        ...

        // Add resource to deployment
        deployment.addClass(MyResource.class);

        container.start();
        container.deploy(deployment);
    }
}

Maintenant que notre uberJar est exécutable, on peut déployer une application Wildfly-Swarm de 2 manières :

  • Via le plugin maven, en lançant la commande suivante :
    mvn wildfly-swarm:run
  • A partir du jar :
    java -jar target/restful-endpoint-swarm.jar

Les différences entre Wildfly-Swarm et Spring boot

Le tableau ci-dessous présente quelques données pour comparer la taille des jars, le temps de démarrage, la mémoire occupée etc. Il faut noter que ces données sont assez anciennes et ne prennent pas en compte les dernières versions des technologies respectives.

Container Far jar Size Bootstart Time Memory footprint Deamon Threads Live Threads
Spring Boot Jetty 20mb 12.4s 31 – 45mb 11 28
Spring Boot Tomcat 18mb 10.2s 35 – 40mb 16 18
Wildfly Swarm 31mb 4.1s 12 – 40mb 12 37

De manière générale, on peut constater qu’un uberJar Wildfly-Swarm dans sa version la plus minimaliste est quand même d’une taille plus importante qu’un jar généré par Spring boot. Cela est dû à l’inclusion du conteneur swarm dérivé de Wildfly. En revanche, il semble que le temps de démarrage soit plus rapide que Spring-boot, même si cela dépend de la configuration de Wildfly-Swarm.

Mis à part ces chiffres, ces deux technologies partagent les mêmes concepts en ce qui concerne la génération d’un jar exécutable et déployable, la principale différence étant qu’elles ne partagent pas la même philosophie. En effet, au départ, Spring-Boot a été imaginé afin de créer une application Spring rapidement avec très peu de configuration. Il est donc idéal pour la création de nouveaux projets. En revanche Wildfly-Swarm, de par sa nature, permet de packager des applications Java EE existantes assez facilement juste en ajoutant un plugin maven. Wildfly-Swarm est donc très pratique pour migrer des applications Monolithiques vers des applications de types microservices. Ainsi, il n’existe pas de réel avantage à utiliser une technologie plutôt que l’autre, tout dépend du contexte et, finalement, bien que similaires, les 2 solutions trouvent leurs existences en se complétant.

Quelle valeur ajoutée apporte Java EE dans ce contexte Microservices ?

Comme la plupart le sait, les projets en Java EE sont en général de type “monolithique” en architecture 3-tiers. Les technologies java EE ont été à créées pour répondre à certaines problématiques de l’époque et, aujourd’hui, on se rend compte qu’il y a des limites à ce modèle d’architecture dans certains contextes, comme par exemple dans les cas de maintenance et d’évolutions. Malgré l’émergence des microservices, tous les SI ne sont pas encore capables de migrer vers une architecture microservices car ils présentent trop de couplage entre les services et sont donc trop complexes. Cependant, Java EE est aussi capable de répondre à ces problématiques car, bien qu’assez ancien, c’est un écosystème fiable et soutenu par une large communauté de passionnés actifs et d’entreprises qui participent à faire évoluer cette plateforme.

Ainsi, la grande force de Java EE est de pouvoir proposer des solutions “standards” approuvées par une grosse communauté, capables de s’adapter aux problèmes actuels. D’où la création de Wildfly-Swarm. Rappelez-vous, en introduction je vous ai parlé de MicroProfile, qui est une spécification standards pour la création de microservices en Java EE.

Finalement, pourquoi Wildfly-Swarm est un choix qui peut être intéressant pour réaliser des microservices ?

Il existe bien entendu d’autres alternatives à Wildfly-Swarm pour la création de microservices, cependant Wildfly-Swarm convient de par sa facilité à packager des applications Java EE existantes. Il est donc adapté pour les transitions de type monolithique vers microservices. De plus Wildfly-Swarm est encore tout récent (1 an d’existence) et, avec la mise en place et la participation de la communauté sur la spécification “MicroProfile”, il pourra encore s’améliorer avec des features en accord avec les attentes des entreprises.

© SOAT
Toute reproduction interdite sans autorisation de la société SOAT

Nombre de vue : 3539

COMMENTAIRES 3 commentaires

  1. Christelle dit :

    Très bon article, pointu. Merci pour le détail et les explications

  2. Anthony S dit :

    Bonjour,

    Ton article est très intéressant et je voudrais poser deux questions sur un cas réel.

    Une application 3/3 ayant des (gros) services s’appelant entre eux pour garantir une logique de traitement : On va créer et persister un objet via un service qui va en appeler d’autres pour créer d”autres objets directement liés au modèle de données.
    Comment penser micro service dans ce cas ? n’y a t’il pas une limite et un risque de micro services s’appelant entre eux de manière non coordonnée et aveugle. ?

    Une application discute avec une autre pour récupérer des données. Les 2 applications appartiennent au même métier (finance pare exemple) mais ont des périmètres fonctionnels différents Une partie de l”équipe pense que ces deux appli doivent être fusionnées , l’autre non (avec discussion sur le fait de les laisser indépendantes ou de faire des micro services).
    Quel est votre avis.

  3. Bonjour Anthony,

    Merci pour ton commentaire, je vais essayer de répondre au mieux à tes questions:

    1 – Comment penser micro service dans ce cas ? n’y a t’il pas une limite et un risque de micro services s’appelant entre eux de manière non coordonnée et aveugle. ?

    Pour répondre à ta première question, effectivement il y a risque d’enchevêtrement de services s’appelant entre eux, cette problématique relève plus d’une logique de design que de technique à vrai dire. En général, la création de micro-services n’est pertinente que lorsque les domaines fonctionnels sont bien définis, et cela n’est possible que lorsque l’application était au départ monolithique. C’est pour cela que partir from scratch vers une application micro-services est assez compliqué.

    2-Une application discute avec une autre pour récupérer des données. Les 2 applications appartiennent au même métier (finance pare exemple) mais ont des périmètres fonctionnels différents Une partie de l”équipe pense que ces deux appli doivent être fusionnées , l’autre non (avec discussion sur le fait de les laisser indépendantes ou de faire des micro services).
    Quel est votre avis ?

    Dans ce cas précis, je pense que la création de micro-services est intéressante si les services sont appelés par plusieurs autres domaines fonctionnels. Si les 2 services s’appellent entre eux, et uniquement entre eux, c’est plus simple de les rassembler pour la maintenabilité de l’application.

    Voilà j’espère que tu as pu obtenir les réponses à tes questions, il est compliqué d’avoir un avis objectif sur ce genre de questions car ces problématiques sont assez récentes. En tout cas je te remercie pour ton intérêt.

AJOUTER UN COMMENTAIRE