Quarkus : modernisation d'applications Ă  partir de l'exemple helloworld de JBoss EAP Quickstart

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

Quarkus : modernisation d'applications Ă  partir de l'exemple helloworld de JBoss EAP Quickstart

Le post précédent parlait de la façon dont Quarkus combine MicroProfile et Spring. Rappelons que Quarkus 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 l'application helloworld du référentiel Red Hat JBoss Enterprise Application Platform (JBoss EAP) Quickstart, 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 Red Hat Application Migration Toolkit. AprĂšs cela, 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 helloworld.

Lors de la rédaction de ce post, des guides ont été utilisés sur Quarkus, principalement Créer votre premiÚre application et Construire un exécutable natif.

Acquérons le code

Tout d'abord, créons un clone local du référentiel JBoss EAP quickstarts:

$ 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 ici), 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 127.0.0.1:8080 et vous devriez voir ceci :

Quarkus : modernisation d'applications Ă  partir de l'exemple helloworld de JBoss EAP Quickstart

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

4. Suivez les instructions dans le guide Build and Deploy the Quickstart: 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 Accéder à l'application, ouvrez dans votre navigateur 127.0.0.1:8080/helloworld et nous voyons ceci :

Quarkus : modernisation d'applications Ă  partir de l'exemple helloworld de JBoss EAP Quickstart

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é :

Quarkus : modernisation d'applications Ă  partir de l'exemple helloworld de JBoss EAP Quickstart

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 github.com/quarkusio/quarkus/releases/latest.

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 :

  1. 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 .
  2. Nous supprimons le bloc , car lors de l'utilisation de Quarkus, cette application n'a plus besoin du pom parent de JBoss.
  3. Nous ajoutons la balise et la plaçons sous la balise . Vous pouvez indiquer le numéro de version que vous souhaitez.
  4. Nous supprimons la balise , car cette application n'est plus un WAR, mais un simple JAR.
  5. Nous modifions les dépendances suivantes :
    1. 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.
    2. 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.
    3. 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 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 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 Mode développement).

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 à documentation et de lire comment cela fonctionne dans Quarkus Inject, et donc Contexts and Dependency Injection (CDI). Ouvrons donc le guide Contexts and Dependency Injection et dans la section Bean Discovery 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 JSR 365: Contexts and Dependency Injection for Java 2.0—Default scope.

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 0.0.0.0:8080 (page d'accueil par défaut de Quarkus) et voyons ceci :

Quarkus : modernisation d'applications Ă  partir de l'exemple helloworld de JBoss EAP Quickstart

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 Ă  0.0.0.0:8080/HelloWorld et nous voyons ce qui suit :

Quarkus : modernisation d'applications Ă  partir de l'exemple helloworld de JBoss EAP Quickstart

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 :

Quarkus : modernisation d'applications Ă  partir de l'exemple helloworld de JBoss EAP Quickstart

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 Création d'Uber-Jar.

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 à 0.0.0.0: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 github.com/oracle/graal/releases/tag/vm-19.2.0.1.

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 Building a Native Executable—Prerequisites.

Nous construisons helloworld en un fichier exécutable natif
Lisez le guide Building a Native Executable—Producing a native executable: « 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 0.0.0.0: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

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster