Bonjour à tous dans ce blog, et voici le quatriÚme post de la série sur Quarkus !

parlait de la façon dont Quarkus combine MicroProfile et Spring. Rappelons que il se positionne comme « Java subatomique ultra-rapide », aussi connu comme « une pile Java orientée Kubernetes, optimisée pour GraalVM et OpenJDK HotSpot, construite à partir des meilleures bibliothÚques et normes ». Aujourd'hui, nous allons montrer comment moderniser les applications Java existantes en profitant des capacités de Quarkus, en prenant exemple sur , qui utilise les technologies prise en charge par Quarkus, CDI et Servlet 3.
Il est important de noter que Quarkus et JBoss EAP mettent l'accent sur l'utilisation d'outils largement basĂ©s sur des standards. Vous n'avez pas d'application fonctionnant sur JBoss EAP ? Pas de problĂšme, elle peut facilement ĂȘtre migrĂ©e de votre serveur d'applications actuel vers JBoss EAP Ă l'aide de . AprĂšs cela, la version finale et fonctionnelle du code modernisĂ© sera disponible dans le rĂ©fĂ©rentiel , dans le module .
Lors de la rédaction de ce post, des guides ont été utilisés , principalement et Construire un .
Acquérons le code
Tout d'abord, créons un clone local du référentiel :
$ git clone https://github.com/jboss-developer/jboss-eap-quickstarts.git
Clonage dans 'jboss-eap-quickstarts'...
remote : ĂnumĂ©ration des objets : 148133, fait.
remote : Total 148133 (delta 0), réutilisé 0 (delta 0), pack-réutilisé 148133
Recevoir les objets : 100 % (148133/148133), 59.90 Mo | 7.62 Mo/s, fait.
Résolution des deltas : 100 % (66476/66476), fait.
$ cd jboss-eap-quickstarts/helloworld/
Voyons comment fonctionne le helloworld d'origine
En fait, le sens de cette application est clair d'aprÚs son nom, mais nous allons moderniser son code de maniÚre rigoureuse. Donc d'abord, examinons cette application dans son état d'origine.
Déployons helloworld
1. Ouvrez un terminal et allez dans le répertoire racine de JBoss EAP (vous pouvez le télécharger ), c'est-à -dire dans le dossier EAP_HOME.
2. Démarrez le serveur JBoss EAP avec le profil par défaut :
$ EAP_HOME/bin/standalone.sh
Remarque : sous Windows, utilisez le script EAP_HOME/bin/standalone.bat pour démarrer.
Dans quelques secondes, le journal devrait afficher Ă peu prĂšs ce qui suit :
[org.jboss.as] (Controller Boot Thread) WFLYSRV0025 : JBoss EAP 7.2.0.GA (WildFly Core 6.0.11.Final-redhat-00001) démarré en 3315ms - Démarré 306 des 527 services (321 services sont paresseux, passifs ou à la demande)
3. Ouvrez dans le navigateur :8080 et vous devriez voir ceci :

Fig. 1. Page d'accueil de JBoss EAP.
4. Suivez les instructions dans le guide : nous déployons helloworld et exécutons (depuis le dossier racine du projet) la commande suivante :
$ mvn clean install wildfly:deploy
AprÚs l'exécution réussie de cette commande, nous verrons dans le journal quelque chose comme :
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.224 s
Ainsi, le premier déploiement de l'application helloworld sur JBoss EAP a pris un peu plus de 8 secondes.
Testons helloworld
Agissant strictement selon le guide , ouvrez dans votre navigateur :8080/helloworld et nous voyons ceci :

Fig. 2. Hello World d'origine de JBoss EAP.
Apportons des modifications
Changeons le paramÚtre d'entrée createHelloMessage(String name) de World en Marco :
writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");
Exécutons à nouveau la commande suivante :
$ mvn clean install wildfly:deploy
Puis nous rafraßchissons la page dans le navigateur et voyons que le texte a changé :

Fig. 3. Hello Marco dans JBoss EAP.
Annulons le déploiement de helloworld et terminons le travail de JBoss EAP
Ce n'est pas obligatoire, mais si vous souhaitez annuler le déploiement, cela peut se faire avec la commande suivante :
$ mvn clean install wildfly:undeploy
Pour arrĂȘter l'instance de JBoss EAP, il suffit d'appuyer sur Ctrl+C dans la fenĂȘtre du terminal.
Modernisons helloworld
Nous allons maintenant nous occuper de la modernisation de l'application helloworld d'origine.
Créons une nouvelle branche
Créons une nouvelle branche de travail aprÚs l'achÚvement de l'exécution du projet quickstart :
$ git checkout -b quarkus 7.2.0.GA
Modifions le fichier pom.xml
Nous commencerons à modifier l'application à partir du fichier pom.xml. Pour que Quarkus puisse y insérer des blocs XML, exécutons la commande suivante dans le dossier helloworld :
$ mvn io.quarkus:quarkus-maven-plugin:0.23.2:create
Lors de la rédaction de cet article, la version 0.23.2 était utilisée. Quarkus publie souvent de nouvelles versions ; pour savoir quelle version est la plus récente, vous pouvez consulter le site .
La commande ci-dessus insérera les éléments suivants dans pom.xml :
- La propriété , spécifiant la version de Quarkus utilisée.
- Le bloc pour importer le Quarkus BOM (bill of materials), afin de ne pas ajouter de version pour chaque dépendance Quarkus.
- Le plugin quarkus-maven-plugin, responsable de l'emballage de l'application et fournissant le mode développement.
- Le profil native pour créer des fichiers exécutables de l'application.
De plus, nous apporterons les modifications suivantes manuellement dans pom.xml :
- Nous extrayons la balise du bloc et la plaçons au-dessus de la balise . Ătant donnĂ© qu'Ă l'Ă©tape suivante nous supprimerons le bloc , il est nĂ©cessaire de conserver .
- Nous supprimons le bloc , car lors de l'utilisation de Quarkus, cette application n'a plus besoin du pom parent de JBoss.
- Nous ajoutons la balise et la plaçons sous la balise . Vous pouvez indiquer le numéro de version que vous souhaitez.
- Nous supprimons la balise , car cette application n'est plus un WAR, mais un simple JAR.
- Nous modifions les dépendances suivantes :
- Nous changeons la dépendance javax.enterprise:cdi-api en io.quarkus:quarkus-arc, en supprimant provided, car (selon la documentation) cette extension Quarkus fournit l'injection de dépendance CDI.
- Nous changeons la dépendance org.jboss.spec.javax.servlet:jboss-servlet-api_4.0_spec en io.quarkus:quarkus-undertow, en supprimant provided, car (selon la documentation) cette extension Quarkus fournit un support pour les servlets.
- Nous supprimons la dépendance org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec, car elle est incluse avec les dépendances que nous venons de modifier.
La version du fichier pom.xml avec toutes les modifications se trouve Ă l'adresse .
Notez que la commande mvn io.quarkus:quarkus-maven-plugin:0.23.2:create ne se contente pas de modifier le fichier pom.xml, mais elle ajoute également un certain nombre de composants au projet, à savoir, les fichiers et dossiers suivants :
- Le fichier mvnw et mvnw.cmd ainsi que le dossier .mvn : Maven Wrapper permet d'exécuter des projets Maven avec la version Maven spécifiée sans avoir à installer cette version.
- Le dossier docker (dans le répertoire src/main/) : il contient des exemples de fichiers Dockerfile pour les modes natif et jvm (avec le fichier .dockerignore).
- Le dossier resources (dans le répertoire src/main/) : il contient un fichier application.properties vide et un exemple de page d'accueil Quarkus index.html (voir plus de détails dans Exécuter le helloworld modernisé).
Nous exécutons helloworld
Pour tester l'application, nous utilisons quarkus:dev, qui lance Quarkus en mode développement (voir plus de détails dans cette section du manuel sur ).
Remarque : Cette étape devrait logiquement entraßner une erreur, car nous n'avons pas encore apporté toutes les modifications nécessaires.
Nous exécutons maintenant la commande pour voir comment cela fonctionne :
$ .\/mvnw compile quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------------
[INFO] Building Quickstart: helloworld quarkus
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Listening for transport dt_socket at address: 5005
INFO [io.qua.dep.QuarkusAugmentor] Beginning quarkus augmentation
INFO [org.jbo.threads] JBoss Threads version 3.0.0.Final
ERROR [io.qua.dev.DevModeMain] Ăchec du dĂ©marrage de quarkus : java.lang.RuntimeException: io.quarkus.builder.BuildException: Ăchec de la construction : Ăchec en raison d'erreurs
[error]: Ătape de construction io.quarkus.arc.deployment.ArcProcessor#validate a lancĂ© une exception : javax.enterprise.inject.spi.DeploymentException : javax.enterprise.inject.UnsatisfiedResolutionException : DĂ©pendance insatisfaite pour le type org.jboss.as.quickstarts.helloworld.HelloService et qualificateurs [@Default]
- membre java : org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
- déclaré sur la classe bean [types=[javax.servlet.ServletConfig, java.io.Serializable, org.jboss.as.quickstarts.helloworld.HelloWorldServlet, javax.servlet.GenericServlet, javax.servlet.Servlet, java.lang.Object, javax.servlet.http.HttpServlet], qualificateurs=[@Default, @Any], cible=org.jboss.as.quickstarts.helloworld.HelloWorldServlet]
at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:841)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:214)
at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:106)
at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:249)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Native Method)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at io.quarkus.deployment.ExtensionLoader$1.execute(ExtensionLoader.java:780)
at io.quarkus.builder.BuildContext.run(BuildContext.java:415)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
at java.lang.Thread.run(Thread.java:748)
at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException : Dépendance insatisfaite pour le type org.jboss.as.quickstarts.helloworld.HelloService et qualificateurs [@Default]
- membre java : org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
- déclaré sur la classe bean [types=[javax.servlet.ServletConfig, java.io.Serializable, org.jboss.as.quickstarts.helloworld.HelloWorldServlet, javax.servlet.GenericServlet, javax.servlet.Servlet, java.lang.Object, javax.servlet.http.HttpServlet], qualificateurs=[@Default, @Any], cible=org.jboss.as.quickstarts.helloworld.HelloWorldServlet]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:428)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:371)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:206)
... 14 more
Eh bien, ça ne fonctionne pas... Pourquoi ?
L'exception UnsatisfiedResolutionException pointe vers la classe HelloService, qui est membre de la classe HelloWorldServlet (membre java : org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService). Le problĂšme est que HelloWorldServlet nĂ©cessite une instance de HelloService injectĂ©e, mais elle ne peut pas ĂȘtre trouvĂ©e (bien que ces deux classes soient dans le mĂȘme paquet).
Il est temps de revenir à et de lire comment cela fonctionne dans Quarkus , et donc (CDI). Ouvrons donc le guide Contexts and Dependency Injection et dans la section nous lisons : « Une classe bean qui n'a pas d'annotation bean définitive n'est pas recherchée ».
Regardons la classe HelloService â il est vrai qu'elle n'a pas cette annotation. Il est donc nĂ©cessaire de l'ajouter pour que Quarkus puisse chercher et trouver le bean. Ătant donnĂ© qu'il s'agit d'un objet stateless, nous pouvons tout Ă fait ajouter l'annotation @ApplicationScoped de la maniĂšre suivante :
@ApplicationScoped
public class HelloService {
Remarque : ici, l'environnement de dĂ©veloppement peut vous demander d'ajouter le paquet requis (voir la ligne ci-dessous), et cela devra ĂȘtre fait manuellement, comme ceci :
import javax.enterprise.context.ApplicationScoped;
Si vous avez des doutes sur la portée à utiliser lorsque la portée du bean d'origine n'est pas définie, consultez la documentation .
Nous essayons maintenant de relancer l'application avec la commande .\/mvnw compile quarkus:dev :
$ .\/mvnw compile quarkus:dev
[INFO] Recherche de projets...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[INFO] Construction du Quickstart : helloworld quarkus
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Utilisation de l'encodage 'UTF-8' pour copier les ressources filtrées.
[INFO] Copie de 2 ressources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Changements détectés - recompilation du module !
[INFO] Compilation de 2 fichiers sources vers /home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/target/classes
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Ăcoute pour le transport dt_socket Ă l'adresse : 5005
INFO [io.qua.dep.QuarkusAugmentor] (main) Début de l'augmentation de Quarkus
INFO [io.qua.dep.QuarkusAugmentor] (main) Augmentation de Quarkus terminée en 576ms
INFO [io.quarkus] (main) Quarkus 0.23.2 démarré en 1.083s. à l'écoute sur : http://0.0.0.0:8080
INFO [io.quarkus] (main) Profil dev activé. Live Coding activé.
INFO [io.quarkus] (main) Fonctionnalités installées : [cdi]
Maintenant tout passe sans erreurs.
Nous lançons le helloworld modernisé
Comme indiqué dans le journal, ouvrons dans le navigateur :8080 (page d'accueil par défaut de Quarkus) et voyons ceci :

Fig. 4. Page d'accueil Quarkus dev.
Dans l'annotation WebServlet de cette application, la définition du contexte est la suivante :
@WebServlet("/HelloWorld")
public class HelloWorldServlet extends HttpServlet {
Nous allons donc dans le navigateur Ă :8080/HelloWorld et nous voyons ce qui suit :

Fig. 5 : Page de développement The Quarkus pour l'application Hello World.
Eh bien, tout fonctionne.
Maintenant, nous allons apporter des modifications au code. Notez que la commande ./mvnw compile quarkus:dev fonctionne toujours et nous n'avons pas l'intention de l'arrĂȘter. Essayons maintenant d'appliquer les mĂȘmes â changements trĂšs trivials â au code lui-mĂȘme et voyons comment Quarkus facilite la vie du dĂ©veloppeur :
writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");
Nous enregistrons le fichier et puis actualisons la page web pour voir le message Hello Marco, comme indiqué sur l'écran ci-dessous :

Fig. 6. Page Hello Marco dans Quarkus dev.
Vérifions maintenant la sortie dans le terminal :
INFO [io.qua.dev] (vert.x-worker-thread-3) Changements de fichiers sources détectés, recompilation [/home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/src/main/java/org/jboss/as/quickstarts/helloworld/HelloWorldServlet.java]
INFO [io.quarkus] (vert.x-worker-thread-3) Quarkus arrĂȘtĂ© en 0.003s
INFO [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Début de l'augmentation quarkus
INFO [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Augmentation quarkus terminée en 232ms
INFO [io.quarkus] (vert.x-worker-thread-3) Quarkus 0.23.2 dĂ©marrĂ© en 0.257s. Ăcoute sur : http://0.0.0.0:8080
INFO [io.quarkus] (vert.x-worker-thread-3) Profil dev activé. Live Coding activé.
INFO [io.quarkus] (vert.x-worker-thread-3) Fonctionnalités installées : [cdi]
INFO [io.qua.dev] (vert.x-worker-thread-3) Temps total de remplacement Ă chaud : 0.371s
La mise Ă jour de la page a dĂ©clenchĂ© la dĂ©tection des changements dans le code source, et Quarkus a automatiquement effectuĂ© la procĂ©dure « arrĂȘt-dĂ©marrage ». Et tout cela a Ă©tĂ© rĂ©alisĂ© en seulement 0.371 secondes (voilĂ , la fameuse « Java subatomique ultra-rapide »).
Nous construisons helloworld en paquet JAR
Maintenant que le code fonctionne comme prévu, nous le packons avec la commande suivante :
$ ./mvnw clean package
Cette commande crĂ©e deux fichiers JAR dans le dossier /target : le fichier helloworld-.jar, qui reprĂ©sente l'artefact standard construit par la commande Maven avec les classes et ressources du projet. Et le fichier helloworldârunner.jar, qui reprĂ©sente un JAR exĂ©cutable.
Notez que ce n'est pas un uber-jar, car toutes les dépendances sont simplement copiées dans le dossier /target/lib (et non emballées dans le fichier JAR). Ainsi, pour exécuter ce JAR depuis un autre dossier ou sur un autre hÎte, il faut copier à la fois le fichier JAR et le dossier /lib, en tenant compte du fait que l'élément Class-Path dans le fichier MANIFEST.MF dans le paquet JAR contient une énumération explicite des JARs du dossier lib.
Pour savoir comment créer des applications uber-jar, consultez le guide .
Nous lançons helloworld, conditionné en JAR
Nous pouvons maintenant exécuter notre JAR avec la commande standard java :
$ java -jar ./target/helloworld--runner.jar
INFO [io.quarkus] (main) Quarkus 0.23.2 dĂ©marrĂ© en 0.673s. Ăcoute sur : http://0.0.0.0:8080
INFO [io.quarkus] (main) Profil prod activé.
INFO [io.quarkus] (main) Fonctionnalités installées : [cdi]
Une fois que tout cela est terminé, ouvrez votre navigateur à :8080 et vérifiez que tout fonctionne comme prévu.
Nous construisons helloworld en un fichier exécutable natif
Ainsi, notre helloworld fonctionne comme une application Java autonome, utilisant les dépendances Quarkus. Mais nous pouvons aller plus loin et le transformer en un fichier exécutable natif.
Installation de GraalVM
Tout d'abord, vous devez installer les outils nécessaires :
1. Téléchargez GraalVM 19.2.0.1 depuis .
2. Décompressez l'archive téléchargée :
$ tar xvzf graalvm-ce-linux-amd64-19.2.0.1.tar.gz
3. Allez dans le dossier décompressé.
4. Exécutez la commande ci-dessous pour télécharger et ajouter l'image native :
$ ./bin/gu install native-image
5. Ajoutez le dossier créé à l'étape 2 à la variable d'environnement GRAALVM_HOME :
$ export GRAALVM_HOME={untar-folder}/graalvm-ce-19.2.0.1)
Des informations supplĂ©mentaires et des instructions sur l'installation sur d'autres systĂšmes d'exploitation peuvent ĂȘtre trouvĂ©es dans le guide .
Nous construisons helloworld en un fichier exécutable natif
Lisez le guide : « Maintenant, crĂ©ons un fichier exĂ©cutable natif pour notre application afin de rĂ©duire le temps de dĂ©marrage et la taille sur le disque. Le fichier exĂ©cutable contiendra tout ce qui est nĂ©cessaire pour exĂ©cuter l'application, y compris la machine JVM (en fait, une version minimale, contenant uniquement ce qui est requis pour exĂ©cuter l'application) et notre application elle-mĂȘme. »
Pour créer un fichier exécutable natif, vous devez activer le profil natif de Maven :
$ ./mvnw package -Pnative
Notre construction a pris une minute et 10 secondes, et le fichier final helloworld-runner a été créé dans le dossier /target.
Nous exécutons le fichier exécutable natif helloworld
à l'étape précédente, nous avons obtenu le fichier exécutable /target/helloworld-runner. Maintenant, exécutons-le :
$ ./target/helloworld--runner
INFO [io.quarkus] (main) Quarkus 0.23.2 dĂ©marrĂ© en 0.006s. Ăcoute sur : http://0.0.0.0:8080
INFO [io.quarkus] (main) Profil prod activé.
INFO [io.quarkus] (main) Fonctionnalités installées : [cdi]
Ouvrons à nouveau dans le navigateur :8080 et vérifions que tout fonctionne comme prévu.
Ă suivre !
Nous pensons que la mĂ©thode de modernisation des applications Java prĂ©sentĂ©e dans ce post (mĂȘme sur un exemple simple) mĂ©rite d'ĂȘtre largement appliquĂ©e dans la vie rĂ©elle. Cependant, vous serez probablement confrontĂ© Ă un certain nombre de problĂšmes, dont nous discuterons en partie dans le prochain post, oĂč nous aborderons la maniĂšre de mesurer la consommation de mĂ©moire afin d'Ă©valuer l'amĂ©lioration des performances, une partie importante de l'ensemble du processus de modernisation des applications.
Source : habr.com
