Nota:
- Este tutorial está disponible en un entorno de prácticas gratuitas proporcionado por Oracle.
- Utiliza valores de ejemplo para credenciales, arrendamiento y compartimentos de Oracle Cloud Infrastructure. Al finalizar el laboratorio, sustituya estos valores por valores específicos de su entorno en la nube.
Introducción a GraalVM Native Image
Introducción
En este laboratorio se explica paso a paso cómo crear una aplicación Java nativa en la nube con GraalVM Native Image. Está dirigido a desarrolladores con conocimientos de Java.
La tecnología de GraalVM Native Image compila código Java de forma anticipada en un archivo ejecutable independiente. Solo el código que necesita la aplicación en tiempo de ejecución se agrega al archivo ejecutable.
Un archivo ejecutable producido por Native Image tiene varias ventajas importantes, ya que:
- Utiliza una fracción de los recursos que necesita JVM, por lo que es más barato para ejecutarse
- Comienza en milisegundos
- Ofrece un rendimiento máximo inmediatamente, sin calentamiento
- Se puede empaquetar en una imagen de contenedor ligera para un despliegue más rápido y eficaz
- Presenta una superficie de ataque reducida (más sobre esto en futuros laboratorios)
Muchos de los marcos de microservicios líderes admiten la compilación anticipada con GraalVM Native Image, incluidos Micronaut, Spring, Helidon y Quarkus.
Además, hay plugins de Maven y Gradle para Native Image para que pueda crear, probar y ejecutar fácilmente aplicaciones Java como archivos ejecutables.
Nota: Oracle Cloud Infrastructure (OCI) proporciona GraalVM Enterprise sin costo adicional.
Tiempo de laboratorio estimado: 45 minutos
Objetivos del laboratorio
En esta práctica, realizará las siguientes tareas:
- Conéctese a un host remoto en Oracle Cloud. Desarrollará la aplicación en un host de recursos informáticos de Oracle Cloud.
- Crear y ejecutar una aplicación Java, mediante GraalVM
- Convierta una aplicación Java en un archivo ejecutable mediante GraalVM Native Image
- Crear un archivo ejecutable que funcione con las funciones dinámicas de Java
- Uso del plugin de Maven GraalVM para crear archivos ejecutables con GraalVM Native Image
NOTA: si ve el icono de portátil en el laboratorio, debe hacer algo, como introducir un comando. Manténgase atento a ello.
# This is where we you will need to do something
PASO 1: conexión a un host remoto y comprobación del entorno de desarrollo
Un host remoto proporciona su entorno de desarrollo: una instancia informática de OCI con Oracle Linux 8, 1 CPU y 32 GB de memoria.
El entorno de escritorio Luna Labs se mostrará antes de que el host remoto esté listo, lo que puede tardar hasta dos minutos.
La conexión al host remoto se realiza mediante la ejecución de un script de configuración en el entorno de Luna Desktop. Este script está disponible en el separador Recursos
-
En el escritorio, haga doble clic en el icono Luna-Lab.html. Se abre la página para mostrar las credenciales y la información de Oracle Cloud Infrastructure específicas de su laboratorio.
-
Se mostrará el separador Recursos. Tenga en cuenta que el engranaje que se muestra junto al título Recursos girará mientras la instancia informática se aprovisiona en la nube de teh.
-
Cuando se aprovisiona la instancia, esto puede tardar hasta 2 minutos, verá lo siguiente en el separador Recursos.
-
Copie la secuencia de comandos de configuración, que configura el entorno de código VS, en la ficha Recursos. Haga clic en el enlace Ver detalles para mostrar la configuración. Copie esto como se muestra en la captura de pantalla siguiente.
-
Abra un terminal, como se muestra en la captura de pantalla siguiente:
-
Pegue el código de configuración en el terminal, que le abrirá VS Code.
¡Y ha terminado! Enhorabuena, ahora se ha conectado correctamente a un host remoto en Oracle Cloud.
Nota sobre el entorno de desarrollo
Utilizará GraalVM Enterprise 21 como plataforma Java para este laboratorio. GraalVM es una distribución de JDK de alto rendimiento de Oracle basada en la solución segura y de confianza de Oracle Java SE.
Su entorno de desarrollo viene preconfigurado con GraalVM y las herramientas de Native Image necesarias para este laboratorio.
Puede comprobar fácilmente que ejecutando estos comandos en el terminal: puede crear un terminal desde el código VS, Terminal > New Terminal
:
java -version
native-image --version
PASO 2: creación y ejecución de una aplicación de demostración
Utilizaremos una aplicación de demostración para mostrar GraalVM Native Image: una aplicación Java de línea de comandos que cuenta el número de archivos del directorio actual y sus subdirectorios. Como adicional agradable, la aplicación también calcula el tamaño total de los archivos.
El código fuente de la aplicación está disponible en el host remoto.
Nota en la aplicación de demostración
La aplicación consta de dos archivos Java que se pueden encontrar en el directorio src
:
App.java
: envoltorio para la claseListDir
.ListDir.java
: realiza todo el trabajo. Cuenta los archivos y resume la salida.
La aplicación se puede crear a mano o mediante perfiles de Maven. La configuración de compilación de Maven la proporciona el archivo pom.xml
. Los perfiles de Maven son una gran manera de tener diferentes configuraciones de compilación en un único archivo pom.xml
. Puede obtener más información sobre los perfiles de Maven aquí.
Puede examinar los archivos dentro del código VS abierto.
En esta práctica se utilizarán varios perfiles, cada uno de los cuales tiene una finalidad concreta:
native
: este perfil crea un archivo ejecutable con GraalVM Native Image.java_agent
: este perfil crea la aplicación Java con un agente de rastreo que realiza un seguimiento de todos los usos del código dinámico en la aplicación y captura esta información en archivos de configuración. Más información al respecto más adelante.
Puede utilizar un perfil de Maven concreto transfiriéndolo como parámetro al comando mvn
. El nombre del perfil se agrega al indicador -P
. Puede ejecutar los siguientes comandos desde el terminal dentro del código de VS.
En el siguiente ejemplo se muestra cómo llamar a un perfil native
al crear con Maven:
mvn clean package -Pnative
Ahora que tiene una comprensión básica de lo que la aplicación ejecuta para ver cómo funciona.
-
Construya el proyecto y ejecútelo desde el Terminal que abrimos en VS Code:
mvn clean package exec:exec
El comando anterior hace lo siguiente:
- Limpia el proyecto para eliminar los artefactos generados o compilados.
- Crea un archivo JAR ejecutable que contiene la aplicación. Este archivo JAR será utilizado posteriormente por Native Image.
- Ejecuta la aplicación ejecutando el plugin
exec
.
Debe ver lo siguiente incluido en la salida generada (el número de archivos informados por la aplicación puede variar):
Counting directory: . Total: 15 files, total size = 511.9 KiB [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------
PASO 3: conversión de una aplicación Java en un archivo ejecutable
A continuación, va a crear una versión ejecutable de la aplicación con GraalVM Native Image. Como recordatorio rápido, GraalVM Native Image es una tecnología de compilación anticipada que convierte la aplicación Java en un archivo ejecutable independiente que no requiere que se ejecute JDK, es rápido de iniciar y eficaz.
GraalVM Native Image está preinstalado en el host remoto.
-
Para empezar, compruebe que tiene un archivo JAR compilado en el directorio
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
El archivo que necesitará es
graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar
. -
Genere un archivo ejecutable desde la línea de comandos. No necesita utilizar el plugin de Maven para utilizar GraalVM Native Image, pero puede ayudarle. Ejecute lo siguiente desde el directorio raíz del proyecto,
demo
:native-image -jar ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar --no-fallback -H:Class=oracle.App -H:Name=file-count
Esto generará un archivo ejecutable denominado
file-count
en el directorio actual. -
Ejecute este archivo ejecutable de la siguiente manera:
./file-count
-
Ahora la hora de la aplicación. En primer lugar, ejecútelo como archivo ejecutable y, a continuación, mediante el comando
java
normal:time ./file-count
time java -cp ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar oracle.App
El archivo ejecutable, generado por el comando
native-image
, se ejecuta significativamente más rápido que la aplicación Java correspondiente.
Vamos a profundizar un poco en cómo creó el archivo ejecutable.
¿Qué parámetros ha transferido al comando native-image
en el paso 2 especificado?
-jar
: especifique la ubicación del archivo JAR que contiene la aplicación Java. (También puede especificar la classpath con-cp
).--no-fallback
: no genere una imagen de reserva. (Una imagen de reserva necesita una JVM para ejecutarla y no necesita esto).-H:Class
: especifique la clase que proporciona el método de punto de entrada (métodomain
).-H:Name
: especifique el nombre del archivo ejecutable de salida.
Puede encontrar la documentación completa aquí.
También puede ejecutar la herramienta native-image
mediante el plugin Maven de GraalVM Native Image. El archivo del proyecto pom.xml
(configuración de Maven) contiene el siguiente fragmento que demuestra cómo crear un archivo ejecutable con el plugin:
<!-- 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>
El plugin de Native Image Maven realiza el trabajo pesado de creación del archivo ejecutable. Puede desactivarla mediante la etiqueta <skip>true</skip>
. Tenga en cuenta también que puede transferir parámetros a native-image
a través de las etiquetas <buildArgs/>
.
Puede encontrar la documentación completa sobre el plugin de GraalVM Native Image aquí.
Para crear el archivo ejecutable con el perfil de Maven, ejecute:
mvn clean package -Pnative
La creación de Maven coloca el archivo ejecutable, file-count
, en el directorio target
.
Puede ejecutar el archivo ejecutable de la siguiente manera:
./target/file-count
PASO 4: uso de reflejo: agregación de una dependencia a Log4J
En este paso, creará un archivo ejecutable que funcione con las funciones dinámicas de Java.
Supongamos que desea agregar una biblioteca o algún código a la aplicación que se basa en la reflexión. Un buen candidato para probar la reflexión es el marco de registro Log4J. Ya se ha agregado como dependencia en el archivo pom.xml
del proyecto:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Para cambiar la aplicación para que utilice log4j
, edite el archivo ListDir.java
y elimine los comentarios de algunas líneas.
-
Abra el archivo
ListDir.java
mediante el código VS -
Elimine los comentarios de la línea que declara la importación de
log4j
y, a continuación, elimine los comentarios de las siguientes líneas://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()); } */
-
Guarde el archivo
Ahora que ha agregado el registro a la aplicación, puede ver el resultado de los cambios reconstruyendo y ejecutando.
mvn clean package exec:exec
Debe ver el mismo tipo de salida que vio anteriormente, pero con la adición de más registros.
-
A continuación, cree un archivo ejecutable con el perfil de Maven:
mvn clean package -Pnative
-
Ejecute el archivo ejecutable que ha creado, que ahora contiene el registro:
./target/file-count
Se genera un error:
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
¿Qué ha pasado?
Trabajar con las Funciones Dinámicas de Java
Esta excepción se debe a la agregación de la biblioteca Log4J porque se basa en la reflexión.
La herramienta native-image
realiza un análisis estático agresivo para ver qué clases se utilizan en la aplicación. Para las clases no utilizadas, la herramienta asumirá que no son necesarias. Esto se denomina suposición del "mundo cerrado": todo lo que se debe cargar se debe conocer al crear un archivo ejecutable. Si no se puede encontrar mediante análisis estático, no se incluirá en el archivo ejecutable.
La reflexión es una función principal de Java, por lo que ¿cómo se puede utilizar la reflexión y aprovechar las rápidas que ofrece GraalVM Native Image? Necesita una forma de hacer que la herramienta native-image
conozca cualquier uso de reflexión.
Por suerte, la herramienta native-image
puede leer en los archivos de configuración que especifican todas las clases a las que se hace referencia a través de la reflexión.
Puede hacerlo manualmente, o bien el agente de rastreo de Java que se suministra con el tiempo de ejecución de GraalVM Java puede hacerlo por usted. El agente genera archivos JSON que registran todas las instancias de reflexión, JNI, proxies y acceso a recursos que puede localizar mientras se ejecuta la aplicación.
Nota: Es importante ejercer todas las rutas de código de la aplicación al ejecutar el agente de rastreo para asegurarse de que se identifican todos los casos de reflexión.
Puede encontrar la documentación completa del agente de rastreo aquí.
PASO 5: uso del agente de rastreo
Ahora utilice el agente de rastreo para generar la configuración de reflexión mientras ejecuta la aplicación.
-
Ejecute la aplicación con el agente de rastreo:
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
Observe los archivos de configuración que ha creado el agente de rastreo:
ls -l src/main/resources/META-INF/native-image/
Aparecerá lo siguiente en la salida generada:
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
Nota: el proyecto contiene un perfil de Maven que puede hacer esto por usted. Ejecute el siguiente comando para utilizar el agente de rastreo:
mvn clean package exec:exec -Pjava_agent
-
Ahora vuelva a crear el archivo ejecutable. Esta vez se aplicarán los archivos de configuración producidos por el agente de rastreo:
mvn package -Pnative
-
Por último, ejecute el archivo generado:
time ./target/file-count
El archivo ejecutable funciona y produce mensajes de log en la salida, como se esperaba.
Esto funciona porque los archivos generados por el agente de rastreo han registrado las clases a las que hace referencia la reflexión. La herramienta native-image
ahora sabe que se utilizan en la aplicación y, por lo tanto, no las excluye del archivo ejecutable generado.
Nota sobre la posición del parámetro -agentlib
Tenga en cuenta que los parámetros de agente deben presentarse antes que cualquier parámetro -jar
o -classpath
. También debe especificar un directorio en el que escribir los archivos. La ubicación recomendada está en src/main/resources/META-INF/native-image
. La herramienta native-image
selecciona automáticamente los archivos colocados en esta ubicación.
Nota sobre la configuración de la generación del archivo ejecutable
También puede transferir parámetros a la herramienta native-image
mediante un archivo de propiedades Java (por defecto src/main/resources/META-INF/native-image/native-image.properties
). Hay un archivo de ejemplo en el directorio demo
para ofrecerle una idea de lo que puede hacer con él.
Conclusiones
En este laboratorio, ha probado varias funciones de GraalVM Native Image:
- Cómo generar un archivo ejecutable rápido desde una aplicación de línea de comandos Java
- Cómo utilizar Maven para crear un archivo ejecutable
- Cómo utilizar el agente de rastreo para automatizar el proceso de seguimiento y registro de la reflexión
Escriba aplicaciones Java en la nube eficientes, más seguras y ampliables al instante con GraalVM Native Image.
Más información
- Vea una presentación del arquitecto de Native Image, Christian Wimmer GraalVM Native Image: análisis estático a gran escala para Java
- Documentación de referencia de GraalVM Native Image
Más recursos de aprendizaje
Explore otras prácticas en docs.oracle.com/learn o acceda a contenido de aprendizaje más gratuito en el canal YouTube de Oracle Learning. Además, visite education.oracle.com/learning-explorer para convertirse en un explorador de formación de Oracle.
Para obtener documentación sobre los productos, visite Oracle Help Center.
GraalVM Native Image Quick Start
F51537-04
March 2022
Copyright © 2022, Oracle and/or its affiliates.