Remarque :

Introduction à GraalVM Native Image

Introduction

Cet atelier vous guide étape par étape dans le processus de création d'une application Java native dans le cloud avec GraalVM Native Image. Il s'adresse aux développeurs connaissant Java.

La technologie GraalVM Native Image compile le code Java à l'avance dans un fichier exécutable autonome. Seul le code requis lors de l'exécution par l'application est ajouté au fichier exécutable.

Un fichier exécutable produit par Native Image présente plusieurs avantages importants, en ce sens qu'il :

Nombre des principaux cadres de travail de microservices prennent en charge la compilation anticipée avec GraalVM Native Image, y compris Micronaut, Spring, Helidon et Quarkus.

En outre, il existe des modules d'extension Maven et Gradle pour Native Image afin que vous puissiez facilement créer, tester et exécuter des applications Java en tant que fichiers exécutables.

Remarque : Oracle Cloud Infrastructure (OCI) fournit GraalVM Enterprise sans frais supplémentaires.

Temps de laboratoire estimé : 45 minutes

Objectifs du laboratoire

Dans cet exercice, vous allez effectuer les tâches suivantes :

REMARQUE : Si l'icône de l'ordinateur portable apparaît dans l'exercice, vous devez exécuter une commande, par exemple. Gardez un oeil pour cela.

# This is where we you will need to do something

Etape 1 : connexion à un hôte distant et vérification de l'environnement de développement

Votre environnement de développement est fourni par un hôte distant : une instance de calcul OCI avec Oracle Linux 8, 1 UC et 32 Go de mémoire.
L'environnement de bureau Luna Labs s'affichera avant que l'hôte distant soit prêt, ce qui peut prendre jusqu'à deux minutes.

La connexion à votre hôte distant s'effectue via l'exécution d'un script de configuration dans votre environnement Luna Desktop. Ce script est disponible via l'onglet Ressources

  1. Dans le bureau, cliquez deux fois sur l'icône Luna-Lab.html. La page apparaît pour afficher les informations d'identification et les informations d'identification Oracle Cloud Infrastructure propres à l'exercice.

  2. L'onglet Ressources s'affiche. Le graphique affiché en regard du titre Ressources tourne tandis que l'instance de calcul est provisionnée dans le cloud de thé.

  3. Une fois l'instance provisionnée, cette opération peut prendre jusqu'à 2 minutes. Les éléments suivants apparaissent dans l'onglet Ressources.

    Luna - Onglet Ressources

  4. Copiez le script de configuration, qui configure votre environnement VS Code, à partir de l'onglet Ressources. Cliquez sur le lien Visualiser les détails pour afficher la configuration. Copiez-le comme indiqué dans la capture d'écran ci-dessous.

    Script de configuration de copie

  5. Ouvrez un terminal, comme indiqué dans la capture d'écran ci-dessous :

    Ouvrir le terminal

  6. Collez le code de configuration dans le terminal, qui va ouvrir VS Code pour vous.

    Coller le terminal 1

    Coller le terminal 2

Et tu as fini ! Félicitations. Vous êtes maintenant connecté à un hôte distant dans Oracle Cloud !

Remarque sur l'environnement de développement

You will use GraalVM Enterprise 21, as the Java platform for this lab. GraalVM is a high performance JDK distribution from Oracle built on the trusted and secure Oracle Java SE.

Votre environnement de développement est préconfiguré avec GraalVM et les outils Native Image requis pour cet atelier.

Vous pouvez facilement vérifier qu'en exécutant ces commandes dans le terminal, vous pouvez créer un terminal à partir du code VS, Terminal > New Terminal :

java -version

native-image --version

Etape 2 : création et exécution d'une application de démonstration

Nous utiliserons une application de démonstration pour présenter GraalVM Native Image : une application de ligne de commande Java qui compte le nombre de fichiers contenus dans le répertoire actuel et ses sous-répertoires. En complément, l'application calcule également la taille totale des fichiers.

Le code source de l'application est disponible sur l'hôte distant.

Remarque sur l'application de démonstration

L'application se compose de deux fichiers Java qui se trouvent dans le répertoire src :

L'application peut être créée manuellement ou à l'aide de profils Maven. La configuration de build Maven est fournie par le fichier pom.xml. Les profils Maven sont un excellent moyen d'avoir différentes configurations de build dans un seul fichier pom.xml. Pour en savoir plus sur les profils Maven, cliquez ici.

Vous pouvez parcourir les fichiers figurant dans le code VS ouvert.

Plusieurs profils seront utilisés dans cet exercice, chacun ayant un but particulier :

  1. native : ce profil crée un fichier exécutable à l'aide de GraalVM Native Image.
  2. java_agent : ce profil crée l'application Java avec un agent de suivi qui suit toutes les utilisations du code dynamique dans votre application et capture ces informations dans des fichiers de configuration. Pour en savoir plus, consultez la suite.

Vous utilisez un profil Maven particulier en le transmettant en tant que paramètre à la commande mvn. Le nom du profil est ajouté à la fin de l'indicateur -P. Vous pouvez exécuter les commandes suivantes depuis le terminal dans le code VS.

L'exemple ci-dessous montre comment appeler un profil native lors de la création avec Maven :

mvn clean package -Pnative

Maintenant que vous avez une connaissance de base de ce que l'application exécute pour voir comment elle fonctionne.

  1. Créez le projet et exécutez-le, à partir du terminal que nous avons ouvert dans VS Code :

    mvn clean package exec:exec
    

    La commande ci-dessus :

    1. Nettoie le projet pour enlever les artefacts générés ou compilés.
    2. Crée un fichier JAR exécutable contenant l'application. Ce fichier JAR sera utilisé ultérieurement par Native Image.
    3. Exécute l'application en exécutant le module d'extension exec.

    Les éléments suivants doivent être inclus dans la sortie générée (le nombre de fichiers signalés par l'application peut varier) :

    Counting directory: .
    Total: 15 files, total size = 511.9 KiB
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    

Etape 3 : transformer une application Java en fichier exécutable

Vous allez ensuite créer une version exécutable de l'application à l'aide de GraalVM Native Image. Pour rappel, GraalVM Native Image est une technologie de compilation à l'avance qui convertit votre application Java en un fichier exécutable autonome qui ne nécessite pas d'exécution de JDK, rapide à démarrer et efficace.

GraalVM Native Image est préinstallé sur l'hôte distant.

  1. Pour commencer, vérifiez que vous disposez d'un fichier JAR compilé dans votre répertoire target :

    ls ./target
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 archive-tmp
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 classes
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 generated-sources
    -rw-rw-r-- 1 krf krf  496273 Mar  4 11:38 graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar
    -rw-rw-r-- 1 krf krf    7894 Mar  4 11:38 graalvmnidemos-1.0-SNAPSHOT.jar
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 maven-archiver
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 maven-status
    

    Le fichier dont vous aurez besoin est graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar.

  2. Générez un fichier exécutable à partir de la ligne de commande. Vous n'avez pas besoin d'utiliser le module d'extension Maven pour utiliser GraalVM Native Image, mais cela peut vous aider. Exécutez la commande suivante à partir du répertoire racine du projet, demo :

    native-image -jar ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar --no-fallback -H:Class=oracle.App -H:Name=file-count
    

    Cette opération génère un fichier exécutable appelé file-count dans le répertoire en cours.

  3. Exécutez ce fichier exécutable comme suit :

    ./file-count
    
  4. L'heure actuelle de l'application. Commencez par l'exécuter en tant que fichier exécutable, puis à l'aide de la commande java standard :

    time ./file-count
    

    time java -cp ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar oracle.App
    

    Le fichier exécutable, généré par la commande native-image, s'exécute beaucoup plus rapidement que l'application Java correspondante.

Examinons plus en détail la façon dont vous avez créé le fichier exécutable.

Quels sont les paramètres que vous avez transmis à la commande native-image à l'étape 2 indiqués ?

La documentation complète est disponible ici.

Vous pouvez également exécuter l'outil native-image à l'aide du module d'extension Maven de GraalVM Native Image. Le fichier de projet pom.xml (configuration Maven) contient le fragment de code suivant qui explique comment créer un fichier exécutable à l'aide du module d'extension :

<!-- Native Image -->
<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
    <version>${native.maven.plugin.version}</version>
    <extensions>true</extensions>
    <executions>
    <execution>
        <id>build-native</id>
        <goals>
        <goal>build</goal>
        </goals>
        <phase>package</phase>
    </execution>
    </executions>
    <configuration>
        <skip>false</skip>
        <imageName>${exe.file.name}</imageName>
        <mainClass>${app.main.class}</mainClass>
        <buildArgs>
            <buildArg>--no-fallback</buildArg>
            <buildArg>--report-unsupported-elements-at-runtime</buildArg>
        </buildArgs>
    </configuration>
</plugin>

Le module d'extension Maven Native Image effectue la lourde tâche de création du fichier exécutable. Vous pouvez la désactiver à l'aide de la balise <skip>true</skip>. Vous pouvez également transmettre des paramètres à native-image via les balises <buildArgs/>.

La documentation complète du module d'extension GraalVM Native Image est disponible ici.

Pour créer le fichier exécutable à l'aide du profil Maven, exécutez la commande suivante :

mvn clean package -Pnative

La création Maven place le fichier exécutable file-count dans le répertoire target.

Vous pouvez exécuter le fichier exécutable comme suit :

./target/file-count

Etape 4 : utilisation de la réflexion - Ajout d'une dépendance à Log4J

Cette étape consiste à créer un fichier exécutable qui fonctionne avec les fonctionnalités dynamiques de Java.

Supposons que vous souhaitiez ajouter une bibliothèque ou un code à votre application qui repose sur la réflexion. La structure de journalisation Log4J est un bon candidat pour tester la réflexion. Il est déjà ajouté en tant que dépendance dans le fichier pom.xml du projet :

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

Pour modifier l'application afin qu'elle utilise log4j, modifiez le fichier ListDir.java et annulez le commentaire de quelques lignes.

  1. Ouvrez le fichier ListDir.java à l'aide du code VS.

  2. Annulez le commentaire de la ligne qui déclare l'import log4j, puis annulez le commentaire des lignes suivantes :

    //import org.apache.log4j.Logger;
    

    //final static Logger logger = Logger.getLogger(ListDir.class);
    

    /*
    // Add some logging
    if(logger.isDebugEnabled()){
        logger.debug("Processing : " + dirName);
    }
    */
    

    /*
    // Add some logging
    if(logger.isDebugEnabled()){
        logger.debug("Processing : " + f.getAbsolutePath());
    }
    */
    
  3. Enregistrez le fichier

    Une fois que vous avez ajouté la journalisation à votre application, vous pouvez visualiser le résultat de vos modifications en les reconstruisant et en les exécutant.

    mvn clean package exec:exec
    

    Vous devriez voir le même type de sortie que précédemment vu, mais avec l'ajout d'une journalisation supplémentaire.

  4. Ensuite, créez un fichier exécutable à l'aide du profil Maven :

    mvn clean package -Pnative
    
  5. Exécutez le fichier exécutable que vous avez créé, qui contient désormais la journalisation :

    ./target/file-count
    

    Cela génère une erreur :

    Exception in thread "main" java.lang.NoClassDefFoundError
            at org.apache.log4j.Category.class$(Category.java:118)
            at org.apache.log4j.Category.<clinit>(Category.java:118)
            at java.lang.Class.ensureInitialized(DynamicHub.java:552)
            at oracle.ListDir.<clinit>(ListDir.java:75)
            at oracle.App.main(App.java:63)
    Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Category
            at java.lang.Class.forName(DynamicHub.java:1433)
            at java.lang.Class.forName(DynamicHub.java:1408)
            ... 5 more
    

    Que t'est-il arrivé ?

Utiliser les fonctionnalités dynamiques de Java

Cette exception est due à l'ajout de la bibliothèque Log4J car elle repose sur la réflexion.
L'outil native-image effectue une analyse statique agressive pour voir quelles classes sont utilisées dans l'application. Pour les classes non utilisées, l'outil suppose qu'elles ne sont pas nécessaires. Il s'agit de l'hypothèse "closed world" : tout ce qui doit être chargé doit être connu lors de la création d'un fichier exécutable. S'il ne peut pas être trouvé par analyse statique, il ne sera pas inclus dans le fichier exécutable.

La réflexion est une fonctionnalité de base de Java. Comment pouvez-vous utiliser la réflexion et tirer parti des accélérations offertes par GraalVM Native Image ? Vous devez disposer d'un moyen de faire connaître à l'outil native-image toutes les utilisations de la réflexion.

Par chance, l'outil native-image peut lire dans des fichiers de configuration qui spécifient toutes les classes référencées par réflexion.

Vous pouvez le faire manuellement, ou l'agent de trace Java fourni avec l'exécution Java GraalVM peut le faire pour vous. L'agent génère des fichiers JSON qui enregistrent toutes les instances de réflexion, JNI, proxies et accès aux ressources qu'il peut localiser pendant l'exécution de votre application.

Remarque : il est important d'utiliser tous les chemins de code de votre application lors de l'exécution de l'agent de suivi afin de vous assurer que tous les cas de réflexion sont identifiés.

La documentation complète relative à l'agent de suivi est disponible ici.

Etape 5 : utilisation de l'agent de trace

A présent, utilisez l'agent de suivi pour générer la configuration de réflexion lors de l'exécution de votre application.

  1. Exécutez l'application avec l'agent de suivi :

    java -agentlib:native-image-agent=config-output-dir=./src/main/resources/META-INF/native-image -cp ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar oracle.App
    

    Examinez les fichiers de configuration créés par l'agent de suivi :

    ls -l src/main/resources/META-INF/native-image/
    

    Les éléments suivants doivent apparaître dans la sortie générée :

    total 56
    -rw-r--r--  1 kfoster  staff     4B Dec  2 19:13 jni-config.json
    -rw-r--r--  1 kfoster  staff    86B Nov  9 20:46 native-image.properties
    -rw-r--r--  1 kfoster  staff    65B Dec  2 19:13 predefined-classes-config.json
    -rw-r--r--  1 kfoster  staff     4B Dec  2 19:13 proxy-config.json
    -rw-r--r--  1 kfoster  staff   521B Dec  2 19:13 reflect-config.json
    -rw-r--r--  1 kfoster  staff   101B Dec  2 19:13 resource-config.json
    -rw-r--r--  1 kfoster  staff     4B Dec  2 19:13 serialization-config.json
    

    Remarque : le projet contient un profil Maven qui peut effectuer cette opération pour vous. Exécutez la commande suivante pour utiliser l'agent de suivi :

    mvn clean package exec:exec -Pjava_agent
    
  2. Recréez maintenant le fichier exécutable. Cette fois, les fichiers de configuration produits par l'agent de suivi seront appliqués :

    mvn package -Pnative
    
  3. Enfin, exécutez le fichier généré :

    time ./target/file-count
    

    Le fichier exécutable fonctionne et génère des messages de journalisation dans la sortie, comme prévu.

Cela fonctionne car les fichiers générés par l'agent de suivi ont enregistré les classes référencées par réflexion. L'outil native-image sait désormais qu'ils sont utilisés dans l'application et ne les exclut donc pas du fichier exécutable généré.

Remarque sur la position du paramètre -agentlib

Les paramètres d'agent doivent apparaître avant tout paramètre -jar ou -classpath. Vous devez également spécifier un répertoire dans lequel écrire les fichiers. L'emplacement recommandé est sous src/main/resources/META-INF/native-image. Les fichiers placés à cet emplacement sont sélectionnés automatiquement par l'outil native-image.

Remarque sur la configuration de la génération du fichier exécutable

Vous pouvez également transmettre des paramètres à l'outil native-image à l'aide d'un fichier de propriétés Java (par défaut, src/main/resources/META-INF/native-image/native-image.properties). Il existe un exemple de fichier dans le répertoire demo pour vous donner une idée de ce que vous pouvez faire avec lui.

Conclusions

Dans cet atelier, vous avez testé plusieurs fonctionnalités GraalVM Native Image :

  1. Générer un fichier exécutable rapide à partir d'une application de ligne de commande Java
  2. Utilisation de Maven pour créer un fichier exécutable
  3. Comment utiliser l'agent de suivi pour automatiser le processus de suivi et d'enregistrement de la réflexion

Ecrivez des applications Java natives du cloud efficaces, plus sécurisées et évolutives et instantanément avec GraalVM Native Image !

En savoir plus

Ressources de formation supplémentaires

Explorez d'autres exercices sur docs.oracle.com/learn ou accédez à davantage de contenu d'apprentissage gratuit sur le canal Oracle Learning YouTube. De plus, visitez le site education.oracle.com/learning-explorer pour devenir Oracle Learning Explorer.

Pour consulter la documentation du produit, consultez le centre d'aide Oracle.