Profile Software Services

Cómo crear tu primera aplicación Quarkus paso a paso

Dedicamos una entrada anterior a exponer las características generales de Quarkus y cómo proporciona una solución para adaptar Java al mundo de la computación en la nube. En este post vamos a crear nuestra primera aplicación Quarkus. Te enseñamos cómo hacerlo paso a paso.

Desarrollo de una aplicación Quarkus

A continuación, vamos a desarrollar una aplicación Quarkus a través de unos sencillos pasos. Lo primero que debes hacer es asegurarte de disponer de los siguientes requisitos previos.

Requisitos

Creación del proyecto Quarkus

Para crear un proyecto Quarkus podemos usar el inicializador disponible en https://code.quarkus.io/ (similar al Initializr de Spring).

Se nos ofrece una lista de extensiones que podemos incluir en nuestra nueva aplicación.

Crear un proyecto Quarkus

Como la nuestra va a ser una aplicación que meramente exponga un endpoint, elegimos RESTEasy Reactive JSON-B, y luego damos al botón de «Generar». Como herramienta de construcción hemos elegido Maven. Nos descargamos el proyecto, lo descomprimimos en una carpeta y lo importamos en nuestro IDE. 

Una vez creado el proyecto, el plugin Quarkus de Maven nos permite gestionar las extensiones. De modo que si, por ejemplo, hubiésemos creado un proyecto plano, podríamos añadir resteasy-jsonb mediante:

mvnw quarkus:add-extension -Dextension=resteasy-jsonb

Puedes ver las extensiones disponibles con mvnw quarkus:list-extensions.

El proyecto generado tendrá esta estructura:

Al examinar el contenido comprobamos que no hay ninguna clase de arranque de la aplicación. Y es que, a diferencia de Spring (que marcaría con @SpringBootApplication la clase principal de la aplicación), en Quarkus no es necesario disponer de una clase arranque semejante (aunque también lo permite, mediante la anotación @QuarkusMain).

Nuestro endpoint de ejemplo está definido en la clase GreetingResource.java: devolverá un saludo cuando se hagan peticiones a /hello.

/code-with-quarkus/src/main/java/org/acme/GreetingResource.java

@Path y @GET son anotaciones  del estándar JAX-RS para definir cómo se accede al servicio. En Spring corresponderían a @RequestMapping y @GetMapping, respectivamente. Con @Produces especificamos el tipo de retorno. 

Ejecución de la aplicación Quarkus en modo de desarrollo

El modo de desarrollo o dev mode nos permite ejecutar la aplicación y hacer cambios sobre la marcha, que se verán reflejados inmediatamente en la aplicación sin que sea necesario reiniciarla. Quarkus se encarga de recompilarla y recargarla según guardemos nuestros cambios en el código. 

Para ejecutar en modo desarrollo hacemos:

mvnw compile quarkus:dev

El modo de desarrollo estará activo mientras esté abierto el terminal. Se obtendrán las librerías necesarias la primera vez que se construya la aplicación y, a continuación, ésta arrancará. Por defecto, la aplicación tiene activo el puerto de depuración 5005. Si no queremos hacer depuración, se puede usar el parámetro -Ddebug=false

mvnw compile quarkus:dev -Ddebug=false

Para acceder al endpoint navegamos a la URL: https://locall.host/8080/

Si ahora en el IDE abrimos GreetingResource.java, cambiamos

return "Hello from RESTEasy Reactive"; 

por

 return "hola";

y grabamos, al recargar la página en el navegador veremos incorporado nuestro cambio sin necesidad de reiniciar.

Detendremos la aplicación con CTRL-C-.

Inyección de dependencias en Quarkus

Antes que nada, vamos a parametrizar el mensaje de salida mediante propiedades. En el fichero application.properties definimos las dos siguientes:

/code-with-quarkus/src/main/resources/application.properties

Y las incorporamos en GreetingResource.java mediante @ConfigProperty, una anotación con una función similar a @Value de Spring.

/code-with-quarkus/src/main/java/org/acme/GreetingResource.java

Al recargar el navegador tendremos:

Para que podamos pasar los tests, cambiamos GreetingResourceTest.java, que se generó con el proyecto, para adecuarlo a nuestra nueva salida:

/code-with-quarkus/src/test/java/org/acme/GreetingResourceTest.java

Equivalencias de la inyección de dependencias entre Spring y Quarkus

En general, si conocemos Spring, la forma de organizar nuestro código en Quarkus va a ser muy similar. Esta tabla recoge las equivalencias entre la inyección de dependencias de Spring y las de Quarkus, que sigue el estándar de Jakarta EE (antes conocido como Java EE) y Microprofile:

SpringCDI / MicroProfile
@Autowired@Inject
@Qualifier@Named
@Value@ConfigProperty
@Component@Singleton
@Service@Singleton
@Repository@Singleton
@Configuration@ApplicationScoped
@Bean@Produces
@ScopeNo hay correspondencia directa. Dependiendo del valor de @Scope, se usará @Singleton, @ApplicationScoped, @SessionScoped, @RequestScoped o @Dependent según se necesite 
@ComponentScanNo hay correspondencia. Quarkus examina todo el classpath en tiempo de construcción.
Equivalencias de la inyección de dependencias entre Spring y Quarkus.

Inyección de dependencias con @Inject

Vamos a ver un ejemplo de inyección de dependencias con @Inject. Recurriremos a un servicio para generar el saludo, en vez de hacerlo directamente en GreetingResource:

/code-with-quarkus/src/main/java/org/acme/service/GreetingService.java

Al implementar el servicio, lo anotaremos con @ApplicationScoped para indicar el ámbito en el que opera la instancia:

/code-with-quarkus/src/main/java/org/acme/service/impl/GreetingServiceImpl.java

En Quarkus/MicroProfile disponemos de los siguientes ámbitos:

AnotaciónMomento de inicializaciónInstancias
@ApplicationScopedCuando es llamado un método de la clase instanciadaUna por aplicación
@SingletonCuando se inyecta en la clase contenedoraUna por aplicación
@DependentCuando se inyecta en la clase contenedoraPara cada punto de inyección
@RequestScopedCuando es llamado un método de la clase instanciadaPara cada petición HTTP
@SessionScopedCuando es llamado un método de la clase instanciadaPara cada sesión
Custome ScopeDepende de la implementaciónDepende de la implementación

Puedes encontrar más información sobre los ámbitos aquí.

Ahora recurrimos a la inyección de dependencias para usar este servicio. Esto lo logramos con @Inject (como hemos visto, similar a @Autowired de Spring).

/code-with-quarkus/src/main/java/org/acme/GreetingResource.java

Si vamos al terminal, comprobaremos que se ha recargado la aplicación con nuestros cambios: 

Eventos en Quarkus

Quarkus proporciona una serie de eventos en el ciclo de vida de la inyección de dependencias. A modo de ejemplo, vamos a atender al inicio y a la destrucción de la instancia del servicio mediante @Observe. Los eventos serán StartupEvent y ShutdownEvent. 

/code-with-quarkus/src/main/java/org/acme/service/impl/GreetingServiceImpl.java

Cuando iniciamos la aplicación se detecta el evento y se escribe en el terminal:

Tienes más información sobre estos eventos aquí.

Empaquetado de la aplicación Quarkus

Para empaquetar nuestra aplicación Quarkus como ejecutable JAR, ejecutamos el comando:

mvnw package

En el directorio target/ aparecerá el JAR code-with-quarkus-1.0.0-SNAPSHOT-runner.jar. Este JAR no contiene todas las dependencias, sino que las obtiene del directorio target/quarkus-app. 

Para obtener un JAR autónomo que contenga todas las dependencias, el llamado uber-JAR, el plugin Maven de Quarkus ofrece la opción quarkus.package.type=uber-jar, que incluiremos en el application.properties, o bien podemos especificarlo en el comando de empaquetado:

mvnw package -Dquarkus.package.type=uber-jar

En ese caso obtendremos dos JAR, el mismo que en el empaquetado normal (renombrado con “original”) y el JAR que incluye todas las librerías y se puede ejecutar autónomamente.

Ejecución del JAR

Probemos a ejecutar nuestro JAR en un terminal con el comando: 

java -jar code-with-quarkus-1.0.0-SNAPSHOT-runner.jar

Si queremos publicar la aplicación en otro puerto, por ejemplo 8081, usaremos -Dquarkus.http.port=8081 (el puerto 8080 se reserva para el modo de desarrollo).

Compilación nativa

Por último, en caso de tener instalado en nuestra máquina la herramienta GraalVM, podemos compilar nativamente mediante:

mvnw package -Dnative -Dquarkus.native.container-build=true

Con ello obtendremos las ventajas adicionales en consumo de memoria y tiempo de arranque que expusimos en nuestro primer post.

Conclusión

En esta entrada hemos creado una aplicación muy sencilla en Quarkus para familiarizarnos con esta herramienta y con sus operaciones básicas, en lo que respecta al desarrollo.

Descubre más contenidos interesantes sobre desarrollo de software en nuestro canal de YouTube. ¡Suscríbete!

¿Te gustaría dar el salto al Cloud Computing para acelerar la innovación y reducir costes? En Profile podemos ayudarte. Contacta ahora con nosotros.

Salir de la versión móvil