Quarkus : modernisation des applications en utilisant Helloworld comme exemple du démarrage rapide de JBoss EAP

Bonjour à tous sur ce blog, voici le quatrième article de la série Quarkus !

Quarkus : modernisation des applications en utilisant Helloworld comme exemple du démarrage rapide de JBoss EAP

Publication précédente portait sur la façon dont Quarkus combine MicroProfile et Spring. Rappelons que quarkus se positionne comme « Java subatomique ultra-rapide », alias « pile Java orientée Kubernetes, adaptée à GraalVM et OpenJDK HotSpot et assemblée à partir des meilleures bibliothèques et standards ». Aujourd'hui, nous allons montrer comment moderniser les applications Java existantes en utilisant les capacités de Quarkus, en utilisant l'exemple applications helloworld du référentiel de démarrage rapide Red Hat JBoss Enterprise Application Platform (JBoss EAP), qui utilise les technologies CDI et Servlet 3 prises en charge par Quarkus.

Il est important de noter ici que Quarkus et JBoss EAP mettent l'accent sur l'utilisation d'outils aussi basés sur des normes que possible. Vous n'avez pas d'application exécutée sur JBoss EAP ? Pas de problème, il peut être facilement migré de votre serveur d'applications actuel vers JBoss EAP en utilisant Boîte à outils de migration d'applications Red Hat. Après quoi la version finale et fonctionnelle du code modernisé sera disponible dans le référentiel github.com/mrizzi/jboss-eap-quickstarts/tree/quarkus, dans le module Bonjour le monde.

Lors de la rédaction de cet article, nous avons utilisé Tutoriels Quarkusprincipalement Création de votre première application et construire un Exécutable natif.

Obtenons le code

Tout d'abord, créons un clone local du référentiel Démarrages rapides de JBoss EAP:

$ git clone https://github.com/jboss-developer/jboss-eap-quickstarts.git
Cloning into 'jboss-eap-quickstarts'...
remote: Enumerating objects: 148133, done.
remote: Total 148133 (delta 0), reused 0 (delta 0), pack-reused 148133
Receiving objects: 100% (148133/148133), 59.90 MiB | 7.62 MiB/s, done.
Resolving deltas: 100% (66476/66476), done.
$ cd jboss-eap-quickstarts/helloworld/

Voyons comment fonctionne le helloworld original

En fait, l'essence de cette application ressort clairement du nom, mais nous moderniserons son code de manière strictement scientifique. Par conséquent, examinons d’abord cette application dans sa forme originale.

Déployer HelloWorld

1. Ouvrez un terminal et allez à la racine du dossier JBoss EAP (vous pouvez le télécharger ici), c'est-à-dire dans le dossier EAP_HOME.

2. Lancez le serveur JBoss EAP avec le profil par défaut :

$ EAP_HOME/bin/standalone.sh

Note: Sous Windows, le script EAP_HOMEbinstandalone.bat est utilisé pour le lancer.

Après quelques secondes, quelque chose comme ceci devrait apparaître dans le journal :

[org.jboss.as] (Controller Boot Thread) WFLYSRV0025: JBoss EAP 7.2.0.GA (WildFly Core 6.0.11.Final-redhat-00001) started in 3315ms - Started 306 of 527 services (321 services are lazy, passive or on-demand)

3. Ouvrir dans un navigateur 127.0.0.1:8080 et on voit ceci :

Quarkus : modernisation des applications en utilisant Helloworld comme exemple du démarrage rapide de JBoss EAP

Riz. 1. Page d'accueil de JBoss EAP.

4. Suivez les instructions du manuel Créer et déployer le démarrage rapide: développez helloworld et exécutez (à partir du dossier racine du projet) la commande suivante :

$ mvn clean install wildfly:deploy

Après avoir exécuté avec succès cette commande, nous verrons quelque chose comme ce qui suit dans le journal :

[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.

Tester HelloWorld

Agir strictement selon les instructions Accéder à l'application, ouvrez dans le navigateur 127.0.0.1:8080/helloworld et on voit ceci :

Quarkus : modernisation des applications en utilisant Helloworld comme exemple du démarrage rapide de JBoss EAP

Riz. 2. Hello World original de JBoss EAP.

Faire des changements

Modifiez le paramètre d'entrée createHelloMessage(String name) de World à Marco :

writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");

Exécutez à nouveau la commande suivante :

$ mvn clean install wildfly:deploy

Ensuite, nous actualisons la page dans le navigateur et constatons que le texte a changé :

Quarkus : modernisation des applications en utilisant Helloworld comme exemple du démarrage rapide de JBoss EAP

Riz. 3. Bonjour Marco dans JBoss EAP.

Annuler le déploiement de helloworld et arrêter JBoss EAP

Ceci est facultatif, mais si vous souhaitez annuler le déploiement, vous pouvez le faire avec la commande suivante :

$ mvn clean install wildfly:undeploy

Pour arrêter votre instance JBoss EAP, appuyez simplement sur Ctrl+C dans la fenêtre du terminal.

Mettre à jour HelloWorld

Modernisons maintenant l'application helloworld originale.

Créer une nouvelle branche

Nous créons une nouvelle branche de travail une fois le projet de démarrage rapide terminé :

$ git checkout -b quarkus 7.2.0.GA

Modification du fichier pom.xml

Nous allons commencer à modifier l'application à partir du fichier pom.xml. Pour permettre à Quarkus d'y insérer des blocs XML, exécutez 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 a été utilisée. Quarkus publie souvent de nouvelles versions, vous pouvez découvrir quelle version est la plus récente sur le site Web github.com/quarkusio/quarkus/releases/latest.

La commande ci-dessus insérera les éléments suivants dans pom.xml :

  • Propriété , qui spécifie la version de Quarkus à utiliser.
  • Bloc d'importer Quarkus BOM (bill of materials), afin de ne pas ajouter de version pour chaque dépendance Quarkus.
  • Le quarkus-maven-plugin est responsable de l'empaquetage de l'application et de la fourniture du mode de développement.
  • Le profil natif pour créer des exécutables d'application.

De plus, nous apportons manuellement les modifications suivantes à pom.xml :

  1. Retirer l'étiquette à partir du bloc et placez-le au dessus de la balise . Parce que dans la prochaine étape, nous supprimerons le bloc , alors vous devez sauvegarder .
  2. Supprimer un bloc , car lors de l'exécution avec Quarkus, cette application n'aura plus besoin d'un pom parent de JBoss.
  3. Ajouter une balise et placez-le sous le tag . Vous pouvez spécifier le numéro de version souhaité.
  4. Supprimer la balise , puisque cette application n'est plus un WAR, mais un JAR classique.
  5. Nous modifions les dépendances suivantes :
    1. Remplacez la dépendance javax.enterprise:cdi-api par io.quarkus:quarkus-arc, en supprimant fourni , puisque (selon la documentation) cette extension Quarkus fournit l'injection de dépendances CDI.
    2. Remplacez la dépendance org.jboss.spec.javax.servlet:jboss-servlet-api_4.0_spec par io.quarkus:quarkus-undertow, en supprimant fourni , car (selon la documentation) cette extension Quarkus prend en charge les servlets.
    3. Nous supprimons la dépendance org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec car elle est fournie avec les dépendances que nous venons de modifier.

La version du fichier pom.xml avec toutes les modifications se trouve à l'adresse github.com/mrizzi/jboss-eap-quickstarts/blob/quarkus/helloworld/pom.xml.

Notez que la commande mvn io.quarkus:quarkus-maven-plugin:0.23.2:create ci-dessus modifie non seulement le fichier pom.xml, mais ajoute également un certain nombre de composants au projet, à savoir les fichiers et dossiers suivants :

  • Le fichier mvnw et mvnw.cmd et le dossier .mvn : Maven Wrapper vous permet d'exécuter des projets Maven d'une version Maven donnée sans installer cette version.
  • Dossier Docker (dans le répertoire src/main/) : il contient des exemples de fichiers Docker pour les modes natif et jvm (ainsi que le fichier .dockerignore).
  • Dossier Resources (dans le répertoire src/main/) : il contient un fichier application.properties vide et un exemple de page de démarrage Quarkus index.html (voir Exécuter le helloworld modernisé pour plus de détails).

Lancez HelloWorld
Pour tester l'application, nous utilisons quarkus:dev, qui lance Quarkus en mode développement (pour plus de détails, voir cette section dans le manuel Mode de développement).

Note: Cette étape entraînera probablement une erreur, puisque nous n'avons pas encore apporté toutes les modifications nécessaires.

Exécutons maintenant la commande pour voir comment elle fonctionne :

$ ./mvnw compile quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[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] Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.jboss.as.quickstarts.helloworld.HelloService and qualifiers [@Default]
	- java member: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
	- declared on CLASS 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], qualifiers=[@Default, @Any], target=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(NativeMethodAccessorImpl.java:62)
	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: Unsatisfied dependency for type org.jboss.as.quickstarts.helloworld.HelloService and qualifiers [@Default]
	- java member: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
	- declared on CLASS 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], qualifiers=[@Default, @Any], target=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

Alors, ça ne marche pas... Pourquoi ?

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 a besoin d'une instance injectée de HelloService et elle est introuvable (même si ces deux classes sont dans le même package).

Il est temps de revenir à documentation et lisez comment cela fonctionne dans Quarkus Injecter, et donc Contextes et injection de dépendances (CDI). Par conséquent, ouvrez le guide Contextes et injection de dépendances et dans la section Découverte des haricots nous lisons : « Une classe de bean qui n’a pas d’annotation définissant le bean n’est pas recherchée. »

Regardons la classe HelloService - elle n'a vraiment pas une telle annotation. Par conséquent, il doit être ajouté pour que Quarkus puisse rechercher et trouver le bean. Et comme il s’agit d’un objet sans état, nous pouvons facilement ajouter l’annotation @ApplicationScoped comme ceci :

@ApplicationScoped
public class HelloService {

Note: ici, l'environnement de développement peut vous demander d'ajouter le package requis (voir la ligne ci-dessous), et vous devrez le faire manuellement, comme ceci :

import javax.enterprise.context.ApplicationScoped;

Si vous avez des doutes sur la portée à utiliser dans le cas où elle n'est pas du tout spécifiée pour le bean source, lisez la documentation JSR 365 : Contextes et injection de dépendances pour Java 2.0 – Portée par défaut.

Maintenant, nous essayons à nouveau de lancer l'application avec la commande ./mvnw compile quarkus:dev :

$ ./mvnw compile quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[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] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to /home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/target/classes
[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] (main) Beginning quarkus augmentation
INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 576ms
INFO  [io.quarkus] (main) Quarkus 0.23.2 started in 1.083s. Listening on: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profile dev activated. Live Coding activated.
INFO  [io.quarkus] (main) Installed features: [cdi]

Maintenant, tout se passe sans erreur.

Lancement du helloworld modernisé
Comme écrit dans le journal, ouvrez-le dans le navigateur 0.0.0.0:8080 (la page de démarrage par défaut de Quarkus) et nous voyons ceci :

Quarkus : modernisation des applications en utilisant Helloworld comme exemple du démarrage rapide de JBoss EAP

Riz. 4. Page de démarrage du développement Quarkus.

L'annotation WebServlet pour cette application contient la définition de contexte suivante :

@WebServlet("/HelloWorld")
public class HelloWorldServlet extends HttpServlet {

Alors allons dans le navigateur 0.0.0.0:8080/HelloWorld et nous voyons ce qui suit :

Quarkus : modernisation des applications en utilisant Helloworld comme exemple du démarrage rapide de JBoss EAP

Riz. 5 : La page de développement Quarkus pour l'application Hello World.

Eh bien, tout fonctionne.

Modifions maintenant le code. Notez que la commande ./mvnw compile quarkus:dev est toujours en cours d'exécution et nous n'avons pas l'intention de l'arrêter. Essayons maintenant d'appliquer les mêmes modifications - les plus triviales - au code lui-même et voyons comment Quarkus facilite la vie du développeur :

writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");

Enregistrez le fichier, puis actualisez la page Web pour voir Hello Marco, comme indiqué dans la capture d'écran ci-dessous :

Quarkus : modernisation des applications en utilisant Helloworld comme exemple du démarrage rapide de JBoss EAP

Riz. 6. Bonjour Marco page dans Quarkus dev.

Vérifions maintenant le résultat dans le terminal :

INFO  [io.qua.dev] (vert.x-worker-thread-3) Changed source files detected, recompiling [/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 stopped in 0.003s
INFO  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Beginning quarkus augmentation
INFO  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Quarkus augmentation completed in 232ms
INFO  [io.quarkus] (vert.x-worker-thread-3) Quarkus 0.23.2 started in 0.257s. Listening on: http://0.0.0.0:8080
INFO  [io.quarkus] (vert.x-worker-thread-3) Profile dev activated. Live Coding activated.
INFO  [io.quarkus] (vert.x-worker-thread-3) Installed features: [cdi]
INFO  [io.qua.dev] (vert.x-worker-thread-3) Hot replace total time: 0.371s

L'actualisation de la page a déclenché la détection des modifications dans le code source et Quarkus a automatiquement effectué une procédure d'arrêt-démarrage. Et tout cela a été réalisé en seulement 0.371 seconde (le voici, ce « Java subatomique ultra-rapide »).

Construire helloworld dans un package JAR
Maintenant que le code fonctionne comme il se doit, intégrons-le avec la commande suivante :

$ ./mvnw clean package

Cette commande crée deux fichiers JAR dans le dossier /target : le fichier helloworld-.jar, qui est un artefact standard assemblé par l'équipe Maven avec les classes et les ressources du projet. Et le fichier helloworld-runner.jar, qui est un JAR exécutable.

Veuillez noter qu'il ne s'agit pas d'un uber-jar, puisque toutes les dépendances sont simplement copiées dans le dossier /target/lib (non regroupées dans un fichier JAR). Par conséquent, afin d'exécuter ce JAR à partir d'un autre dossier ou sur un autre hôte, vous devez y copier à la fois le fichier JAR lui-même et le dossier /lib, étant donné que l'élément Class-Path dans le fichier MANIFEST.MF du package JAR contient une liste explicite des JAR des dossiers lib
Pour apprendre à créer des applications uber-jar, veuillez vous référer au tutoriel Création d'Uber-Jar.

Lancez helloworld emballé dans JAR

Nous pouvons maintenant exécuter notre JAR en utilisant la commande Java standard :

$ java -jar ./target/helloworld-<version>-runner.jar
INFO  [io.quarkus] (main) Quarkus 0.23.2 started in 0.673s. Listening on: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profile prod activated.
INFO  [io.quarkus] (main) Installed features: [cdi]

Une fois tout cela fait, accédez à votre navigateur à l'adresse 0.0.0.0:8080 et vérifiez que tout fonctionne comme il se doit.

Compiler helloworld dans un fichier exécutable natif

Ainsi, notre helloworld fonctionne comme une application Java autonome utilisant les dépendances Quarkus. Mais vous pouvez aller plus loin et le transformer en fichier exécutable natif.

Installation de GraalVM
Tout d'abord, pour cela, vous devez installer les outils nécessaires :

1. Téléchargez GraalVM 19.2.0.1 depuis github.com/oracle/graal/releases/tag/vm-19.2.0.1.

2. Développez l'archive téléchargée :

$ tar xvzf graalvm-ce-linux-amd64-19.2.0.1.tar.gz

3. Accédez au dossier Untar.

4. Exécutez la commande ci-dessous pour télécharger et ajouter l'image native :

$ ./bin/gu install native-image

5. Enregistrez le dossier créé à l'étape 2 dans la variable d'environnement GRAALVM_HOME :

$ export GRAALVM_HOME={untar-folder}/graalvm-ce-19.2.0.1)

Pour plus d'informations et d'instructions d'installation sur d'autres systèmes d'exploitation, consultez le manuel Création d'un exécutable natif – Prérequis.

Construire helloworld dans un fichier exécutable natif
Lecture du manuel Création d'un exécutable natif – Produire un exécutable natif: « Créons maintenant un fichier exécutable natif pour notre application afin de réduire son temps de lancement et la taille du disque. Le fichier exécutable contiendra tout le nécessaire pour exécuter l'application, y compris la JVM (ou plutôt une version tronquée de celle-ci, contenant uniquement ce qui est nécessaire pour exécuter l'application) et notre application elle-même.

Pour créer un fichier exécutable natif, vous devez activer le profil Maven natif :

$ ./mvnw package -Pnative

Notre build a pris une minute et 10 secondes, et le fichier final helloworld—runner f a été créé dans le dossier /target.

Exécutez l'exécutable natif helloworld

À l'étape précédente, nous avons reçu le fichier exécutable /target/helloworld—runner. Maintenant, exécutons-le :

$ ./target/helloworld-<version>-runner
INFO  [io.quarkus] (main) Quarkus 0.23.2 started in 0.006s. Listening on: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profile prod activated.
INFO  [io.quarkus] (main) Installed features: [cdi]

Ouvrez-le à nouveau dans le navigateur 0.0.0.0:8080 et vérifiez que tout fonctionne comme il se doit.

Продолжение следует!

Nous pensons que la méthode de modernisation des applications Java utilisant les capacités de Quarkus évoquée dans cet article (bien qu'en utilisant un exemple simple) devrait être activement utilisée dans la vie réelle. Ce faisant, vous rencontrerez probablement un certain nombre de problèmes, que nous aborderons en partie dans le prochain article, où nous expliquerons comment mesurer la consommation de mémoire pour évaluer les améliorations de performances, une partie importante de l'ensemble du processus de modernisation des applications.

Source: habr.com

Ajouter un commentaire