Capítulo 4. Configuración

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

En este capítulo aprenderás lo siguiente sobre cómo establecer los parámetros de configuración:

  • Cómo configurar un servicio Quarkus

  • Cómo inyectar parámetros de configuración en el servicio

  • Cómo aplicar los valores en función del entorno

  • Cómo configurar correctamente el sistema de registro

  • Cómo crear personalizaciones para el sistema de configuración

4.1 Configurar la Aplicación con Propiedades Personalizadas

Problema

Quieres configurar la aplicación Quarkus con propiedades personalizadas.

Solución

Quarkus utiliza varias especificaciones del Microperfil de Eclipse. Una de ellas es la especificación Configuración; sin embargo, para simplificar la configuración, Quarkus utiliza un único archivo para todas las configuraciones, application.properties, que debe colocarse en la raíz del classpath.

Este archivo puede utilizarse para configurar propiedades de Quarkus como el registro o la ruta por defecto, extensiones de Quarkus como el origen de datos o Kafka, o propiedades personalizadas que definas para la aplicación. Vas a verlas todas en el libro, pero en esta receta, verás esta última.

Abre el archivo src/main/resources/application.properties y añade la siguientepropiedad:

greeting.message=Hello World

Puedes inyectar el valor de la propiedad definida en application.properties utilizando la anotación org.eclipse.microprofile.config.inject.ConfigProperty en un campo.

Abre org.acme.quickstart.GreetingResource.java e inyecta el valor de la propiedad greeting.message:

@ConfigProperty(name = "greeting.message") 1
String message; 2

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
    return message; 3
}
1

Inyecta el valor de la propiedad greeting.message

2

Coloca los campos en el ámbito protegido del paquete

3

Devuelve el valor configurado

Consejo

Por razones de rendimiento al utilizar GraalVM y la reflexión, te animamos a que utilices el ámbito paquete-protegido en los campos que se inyectarán en tiempo de ejecución. Puedes leer más sobre ello en la Guía de Referencia CDI de Quarkus.

En una nueva ventana de terminal, haz una petición a /hello para comprobar que el mensaje de salida es el valor configurado en application.properties:

curl http://localhost:8080/hello

Hello World

Si quieres que un campo de configuración no sea obligatorio y proporcionar un valor por defecto, puedes utilizar el atributo defaultValue de la anotación @ConfigProperty.

Abre el archivo org.acme.quickstart.GreetingResource.java e inyecta el valor de la propiedad greeting.upper-case:

@ConfigProperty(name = "greeting.upper-case",
                defaultValue = "true") 1
boolean upperCase;
@GET
@Path("/optional")
@Produces(MediaType.TEXT_PLAIN)
public String helloOptional() {
    return upperCase ? message.toUpperCase() : message;
}
1

Establece el valor por defecto de la propiedad greeting.upper-case en verdadero

Y en una ventana de terminal, haz una petición a /hello/optional para ver que el mensaje de salida está en mayúsculas:

curl http://localhost:8080/hello/optional

HELLO WORLD

Se admiten propiedades multivalor: sólo tienes que definir el tipo de campo como uno de los siguientes: Arrays, java.util.List o java.util.Set, según tus requisitos/preferencias. El delimitador del valor de la propiedad es una coma (,) y el carácter de escape es la barra invertida (\).

Abre el archivo src/main/resources/application.properties y añade la siguiente propiedad con tres valores:

greeting.suffix=!!, How are you???

Abre org.acme.quickstart.GreetingResource.java e inyecta los valores de la propiedad greeting.suffix:

@ConfigProperty(name = "greeting.suffix")
List<String> suffixes;
@GET
@Path("/list")
@Produces(MediaType.TEXT_PLAIN)
public String helloList() {
    return message + suffixes.get(1);
}

Y en una ventana de terminal haz una petición a /hello/list para ver que el mensaje de salida contiene el segundo sufijo:

curl http://localhost:8080/hello/list

Hello World How are you?

También se admite el formato YAML para configurar la aplicación. En este caso, el archivo se llama application.yaml o application.yml.

Para empezar a utilizar el archivo de configuración YAML, tienes que añadir laextensión config-yaml:

./mvnw quarkus:add-extension -Dextensions="config-yaml"

Dado el siguiente archivo de configuración utilizando el formato properties:

greeting.message=Hello World

%staging.quarkus.http.port=8182

quarkus.http.cors=true
quarkus.http.cors.methods=GET,PUT,POST

El equivalente en formato YAML es el siguiente

greeting:
  message: Hello World 1
"%staging": 2
  quarkus:
    http:
      port: 8182
quarkus:
  http:
    cors:
      ~: true 3
      methods: GET,PUT,POST
1

Las propiedades simples se establecen como una estructura

2

Los perfiles se admiten entre comillas

3

Cuando hay subclaves se utiliza ~ para referirse a la parte no prefijada

Debate

La Configuración de Eclipse MicroProfile viene con los siguientes conversores incorporados para mapear un valor de configuración en un objeto Java:

  • boolean y java.lang.Boolean; los valores de verdadero son true, 1, YES, Y, y ON, mientras que cualquier otro valor se considera false

  • byte y java.lang.Byte

  • short y java.lang.Short

  • int y java.lang.Integer

  • long y java.lang.Long

  • float y java.lang.Float

  • double y java.lang.Double

  • char y java.lang.Character

  • java.lang.Class en función del resultado de la llamada a Class.forName

Si no existe un convertidor incorporado o personalizado, se comprueban los siguientes métodos en el objeto destino. Si existe un convertidor incorporado o personalizado, se utiliza el método descubierto/encontrado para instanciar el objeto convertidor y se pasa el argumento cadena para la conversión :

  • El tipo de destino tiene el método public static T of(String)

  • El tipo de destino tiene el método public static T valueOf(String)

  • El tipo objetivo tiene un constructor público con un parámetro String

  • El tipo de destino tiene el método public static T parse(CharSequence)

4.2 Acceder a las propiedades de configuración mediante programación

Problema

Quieres acceder a las propiedades de configuración mediante programación en lugar de inyectarlas utilizando laanotación org.eclipse.microprofile.config.inject.ConfigProperty.

Solución

Inyecta la clase org.eclipse.microprofile.config.Config en el objeto al que quieras acceder a las propiedades mediante programación.

La especificación de configuración de microperfiles de Eclipse te permite inyectar org.eclipse.microprofile.config.Config para obtener propiedades mediante programación en lugar de inyectar directamente con ConfigProperty.

Abre org.acme.quickstart.GreetingResource.java e inyecta la clase Config:

@Inject 1
Config config;
@GET
@Path("/config")
@Produces(MediaType.TEXT_PLAIN)
public String helloConfig() {
    config.getPropertyNames().forEach( p -> System.out.println(p)); 2

    return config.getValue("greeting.message", String.class); 3
}
1

Utiliza la anotación Inject CDI para inyectar la instancia

2

Ahora puedes acceder a la lista de propiedades

3

La propiedad debe convertirse al tipo final

Puedes acceder a la clase Config sin utilizar el CDI llamando al método ConfigProvider.getConfig().

4.3 Sobrescribir valores de configuración externamente

Problema

Quieres sobrescribir cualquier valor de configuración en tiempo de ejecución.

Solución

Puedes sobrescribir cualquier propiedad en tiempo de ejecución estableciéndola como propiedad del sistema o variable de entorno.

Quarkus te permite sobrescribir cualquier propiedad de configuración estableciéndolacomo propiedad del sistema (-Dproperty.name=value) y/o como variable de entorno (export PROPERTY_NAME=value). Las propiedades del sistema tienen más prioridad que las variables de entorno.

Ejemplos de externalización de estas propiedades pueden ser la URL de una base de datos, el nombre de usuario o la contraseña, porque sólo se conocen en el entorno de destino. Pero debes saber que hay una contrapartida, porque cuantas más propiedades en tiempo de ejecución estén disponibles, menos trabajo previo en tiempo de compilación podrá hacer Quarkus.

Vamos a empaquetar la aplicación utilizada en la Receta 4.1 y anular la propiedad greeting.message estableciendo una propiedad del sistema:

./mvnw clean package -DskipTests

java -Dgreeting.message=Aloha -jar target/getting-started-1.0-SNAPSHOT-runner.jar

En una nueva ventana de terminal, valida que la propiedad se ha anulado de Hello World a Aloha ejecutando:

curl localhost:8080/hello

Aloha

En el caso de las variables de entorno, se admiten tres convenciones de nomenclatura para un nombre de propiedad determinado. Esto se debe a que algunos sistemas operativos sólo permiten caracteres alfabéticos y guiones bajos (_), pero no otros caracteres, como puntos (.). Para admitir todos los casos posibles, se utilizan las siguientes reglas:

  1. Coincidencia exacta (greeting.message).

  2. Sustituye los caracteres no alfanuméricos por guiones bajos (greeting_message).

  3. Sustituye los caracteres no alfanuméricos por guiones bajos y convierte el resto a mayúsculas (GREETING_MESSAGE).

Aquí tienes el archivo application.properties:

greeting.message=Hello World

Puedes anular su valor utilizando cualquiera de los siguientes nombres de variables de entorno, ya que todas ellas son equivalentes:

export greeting.message=Aloha
export greeting_message=Aloha
export GREETING_MESSAGE=Aloha

También hay un lugar especial donde puedes poner el archivo application. properties fuera de la propia aplicación, dentro de un directorio llamado config donde se ejecuta la aplicación. Cualquier propiedad de ejecución definida en ese archivo anulará la configuración por defecto.

Importante

config/application.properties también funciona en modo desarrollo, pero necesitas añadirlo en el directorio de salida de tu herramienta de construcción para que funcione (en el caso de Maven, el directorio de destino; en el caso de Gradle, el de construcción), por lo que debes ser consciente de la necesidad de volver a crearlo al ejecutar la tarea clean.

Aparte de las variables de entorno y del archivo application.properties, también puedes colocar un archivo .env en el directorio de trabajo actual para anular los valores de configuración,siguiendo el formato de las variables de entorno (GREETING_MESSAGE=Aloha).

4.4 Configurar con Perfiles

Problema

Te conviene sobrescribir los valores de configuración en función del entorno en el que estés ejecutando Quarkus.

Solución

Quarkus admite la noción de perfiles de configuración, que te permiten tener varios valores de configuración para la misma propiedad en el mismo archivo y habilitar distintos valores para adaptarlos al entorno en el que estés ejecutando el servicio.

La sintaxis de los perfiles de configuración es %{profile}.config.key=value.

Discute

Quarkus viene con tres perfiles incorporados.

dev

Se activa cuando estás en modo de desarrollo (es decir, quarkus:dev).

prueba

Se activa al ejecutar pruebas.

prod

El perfil por defecto cuando no se ejecuta en modo desarrollo o prueba; no necesitas establecerlo en application.properties, ya que se establece implícitamente.

Abre el archivo src/main/resources/application.properties y configúralo para que inicie Quarkus en el puerto 8181 en modo desarrollo:

%dev.quarkus.http.port=8181

Tras este cambio, inicia el servicio para comprobar de nuevo que el puerto de escucha es el 8181 en lugar del predeterminado (8080):

./mvnw compile quarkus:dev

INFO  [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed
    in 671ms
INFO  [io.quarkus] (main) Quarkus 1.4.1 started in 1.385s. Listening on:
    http://0.0.0.0:8181
INFO  [io.quarkus] (main) Profile dev activated. Live Coding activated.
INFO  [io.quarkus] (main) Installed features:
    [cdi, hibernate-validator, resteasy]

Observa que ahora la dirección de escucha eshttp://0.0.0.0:8181 en lugar de la predeterminada.

Finalmente, retrocede al puerto 8080, elimina la línea %dev.quarkus.http.port=8181 en application.properties para alinearlo con el puerto que se utiliza en el resto del libro.

4.5 Cambiar la configuración del registrador

Problema

Quieres cambiar la configuración de registro por defecto.

Solución

Quarkus utiliza un modelo de configuración unificado en el que todas las propiedades de configuración se colocan en el mismo archivo. En el caso de Quarkus, este archivo es application.properties, y en él puedes configurar muchos aspectos del registro.

Por ejemplo, si quieres cambiar el nivel de registro, sólo tienes que poner quarkus.log.level al nivel mínimo de registro.

Abre src/main/resources/application.properties y añade el siguiente contenido:

quarkus.log.level=DEBUG

Ahora inicia la aplicación para ver que se imprimen muchos mensajes de registro nuevos en la consola:

./mvnw compile quarkus:dev

...
[INFO] --- quarkus-maven-plugin:0.22.0:dev (default-cli) @ getting-started ---
Listening for transport dt_socket at address: 5005
DEBUG [org.jbo.logging] (main) Logging Provider: \
    org.jboss.logging.JBossLogManagerProvider
INFO  [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
DEBUG [io.qua.run.con.ConverterSupport] (main) Populate SmallRye config builder
    with converter for class java.net.InetSocketAddress of priority 200
DEBUG [io.qua.run.con.ConverterSupport] (main) Populate SmallRye config builder
    with converter for class org.wildfly.common.net.CidrAddress of priority 200
Nota

Hemos tenido que abarcar varias líneas para dar formato al libro; hemos utilizado la barra invertida para indicarlo.

También puedes activar el almacenamiento de registros en un archivo mediante la propiedad quarkus.log.file.enable. La salida se escribe por defecto en un archivo llamado quarkus.log:

quarkus.log.file.enable=true
Nota

Mientras estés en desarrollo y trabajando desde el directorio fuente, tu archivo de registro estará en el directorio destino.

4.6 Añadir Registros de Aplicación

Problema

Quieres añadir líneas de registro a tu aplicación.

Solución

La mayoría de las veces, tus aplicaciones necesitan escribir sus propios mensajes de registro y no depender únicamente de los registros por defecto proporcionados por Quarkus. Las aplicaciones pueden utilizar cualquiera de las API admitidas para el registro, y los registros se fusionarán.

Quarkus admite estas bibliotecas de registro:

  • JDK java.util.logging

  • Registro JBoss

  • SLF4J

  • Registro de Apache Commons

Veamos cómo utilizar JBoss Logging para registrar contenidos. Abre org.acme.quickstart.GreetingResource.java y registra un mensaje cuando se llame a un punto final especial:

private static org.jboss.logging.Logger logger =
                org.jboss.logging.Logger.getLogger(GreetingResource.class); 1

@GET
@Path("/log") 2
@Produces(MediaType.TEXT_PLAIN)
public String helloLog() {
    logger.info("I said Hello"); 3
    return "hello";
}
1

Crea la instancia del registrador

2

La sub-ruta del punto final es /log

3

Registros en info

Ahora inicia la aplicación:

./mvnw compile quarkus:dev

En una nueva terminal, haz una petición a /hello/log:

curl http://localhost:8080/hello/log

Si inspeccionas el terminal en el que iniciaste Quarkus, verás el siguiente logline:

INFO  [org.acm.qui.GreetingResource] (executor-thread-1) I said Hello

Debate

El registro se realiza por categorías. Una configuración que se aplica a una categoría también se aplica a todas las subcategorías de esa categoría, a menos que haya una configuración de subcategoría coincidente más específica.

Las categorías están representadas por la ubicación de la clase (es decir, el paquete, o subpaquetes,donde están definidas). Por ejemplo, si quieres establecer el registro de seguridad de Undertowen el nivel de rastreo, tienes que establecer la propiedadquarkus.log.category."io.undertow.request.security".level=TRACEen application.properties.

Siguiendo el ejemplo anterior, restrinjamos las líneas de registro de las clases que residen en org.acme.quickstart (y subclases) para que el nivel mínimo de registro sea WARNING:

quarkus.log.category."org.acme.quickstart".level=WARNING 1
1

Las comillas dobles son obligatorias para establecer la categoría

Si repites la solicitud ahttp://localhost:8080/hello/log, ya no se escribirá el logline.

4.7 Registro avanzado

Problema

Quieres registrar de forma centralizada todos tus servicios.

Solución

Cuando se trabaja con arquitecturas de microservicios y Kubernetes, el registro es algo importante a tener en cuenta, porque cada servicio se registra individualmente; pero como desarrollador u operador, puede que quieras tener todos los registros centralizados en un lugar para poder consumirlos en conjunto.

El registro de Quarkus también admite salida JSON y GELF.

Estos registros pueden escribirse en formato JSON, en lugar de texto plano, para que los procese la máquina, registrando la extensión logging-json:

./mvnw quarkus:add-extension -Dextensions="logging-json"

Utiliza la extensión GELF para producir registros en formato GELF y enviarlos utilizando TCP o UDP.

Elformato de registro Graylog extendido (GELF) lo entienden tres de los sistemas de registro más centralizados que se utilizan hoy en día :

  • Graylog (MongoDB, Elasticsearch, Graylog)

  • ELK (Elasticsearch, Logstash, Kibana)

  • EFK (Elasticsearch, Fluentd, Kibana)

Para empezar a registrar en formato GELF, sólo tienes que añadir laextensión logging-gelf:

./mvnw quarkus:add-extension -Dextensions="logging-gelf"

El código de registro no cambia, por lo que se utilizan las mismas interfaces:

private static org.jboss.logging.Logger logger =
                org.jboss.logging.Logger.getLogger(GreetingResource.class); 1

@GET
@Path("/log") 2
@Produces(MediaType.TEXT_PLAIN)
public String helloLog() {
    logger.info("I said Hello"); 3
    return "hello";
}
1

Crea la instancia del registrador

2

La sub-ruta del punto final es /log

3

Registros en info

El controlador GELF debe configurarse en application.properties:

quarkus.log.handler.gelf.enabled=true 1
quarkus.log.handler.gelf.host=localhost 2
quarkus.log.handler.gelf.port=12201 3
1

Activa la extensión

2

Establece el host al que se envían los mensajes de registro

3

Establece el puerto del punto final

Importante

Si utilizas Logstash (ELK), tienes que activar el complemento de entrada que entiende el formato GELF:

input {
  gelf {
    port => 12201
  }
}
output {
  stdout {}
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
  }
}
Importante

Si utilizas Fluentd (EFK), tienes que activar el plug-in de entrada que entiende el formato GELF:

<source>
  type gelf
  tag example.gelf
  bind 0.0.0.0
  port 12201
</source>

<match example.gelf>
  @type elasticsearch
  host elasticsearch
  port 9200
  logstash_format true
</match>

Debate

El registro de Quarkus también admite el formato syslog por defecto, sin necesidad de añadir ninguna extensión. El formato syslog puede utilizarse en Fluentd como alternativa al formato GELF en Quarkus:

quarkus.log.syslog.enable=true
quarkus.log.syslog.endpoint=localhost:5140
quarkus.log.syslog.protocol=udp
quarkus.log.syslog.app-name=quarkus
quarkus.log.syslog.hostname=quarkus-test
Importante

Necesitas activar el complemento de entrada que entiende el formato syslog en Fluentd:

<source>
  @type syslog
  port 5140
  bind 0.0.0.0
  message_format rfc5424
  tag system
</source>

<match **>
  @type elasticsearch
  host elasticsearch
  port 9200
  logstash_format true
</match>

Si utilizas Kubernetes, la forma más sencilla de registrar es acceder a la consola e instalar en el clúster un gestor central de registros que recoja todas las líneas de registro.

Ver también

Para saber más sobre temas avanzados de registro, visita el siguiente sitio web:

4.8 Configurar con perfiles personalizados

Problema

Quieres establecer valores de configuración diferentes para los perfiles personalizados que has creado.

Solución

Hasta ahora, has visto que Quarkus viene con perfiles incorporados para que puedas establecer distintos valores de configuración para una misma propiedad y habilitarlos según el entorno. Pero con Quarkus, también puedes establecer tus propios perfiles.

Lo único que tienes que hacer es especificar qué perfil quieres activar utilizando la propiedad del sistema quarkus.profile o la variable de entorno QUARKUS_PROFILE. Si ambas están activadas, la propiedad del sistema tiene prioridad sobre lavariable de entorno.

Entonces, lo único que tienes que hacer es crear la propiedad con el nombre del perfil y establecer el perfil actual con ese nombre. Vamos a crear un nuevo perfil de montaje que sobrescriba el puerto de escucha de Quarkus.

Abre el archivo src/main/resources/application.properties y establece que Quarkus se inicie en el puerto 8182 cuando el perfil staging esté activado:

%staging.quarkus.http.port=8182

A continuación, inicia la aplicación con el perfil staging activado:

./mvnw -Dquarkus.profile=staging compile quarkus:dev

INFO  [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed
    in 640ms
INFO  [io.quarkus] (main) Quarkus 0.23.2 started in 1.300s. Listening on:
    http://0.0.0.0:8182
INFO  [io.quarkus] (main) Profile staging activated. Live Coding activated.
INFO  [io.quarkus] (main) Installed features: [cdi, hibernate-validator,
    resteasy]

En este caso, se utiliza el método de la propiedad del sistema, pero también podrías establecerlo utilizando la variable de entorno QUARKUS_PROFILE.

Debate

Si quieres establecer el perfil de ejecución en las pruebas, sólo tienes que establecer la propiedad del sistema quarkus.test.profile al perfil dado en tu script de construcción, por ejemplo, en Maven:

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
    <systemPropertyVariables>
        <quarkus.test.profile>foo</quarkus.test.profile>
        <buildDirectory>${project.build.directory}</buildDirectory>
    </systemPropertyVariables>
</configuration>

o, en Gradle:

test {
    useJUnitPlatform()
    systemProperty "quarkus.test.profile", "foo"
}

También puedes cambiar el perfil de producción por defecto. El perfil incorporado en Quarkus es prod, de modo que cuando ejecutas tu aplicación sin ningún perfil, éste es el que se toma por defecto. Pero puedes cambiarlo en tiempo de compilación para que, sin especificar ningún perfil, tu perfil sea el que se tome por defecto cuando se ejecute la aplicación.

Lo único que tienes que hacer es construir la aplicación utilizando la propiedad del sistema quarkus.profile con el valor del perfil que quieras establecer como predeterminado:

./mvnw package -Pnative -Dquarkus.profile=prod-kubernetes`
./target/getting-started-1.0-runner 1
1

El comando se ejecutará con el perfil prod-kubernetes activado por defecto

4.9 Crear fuentes personalizadas

Problema

Quieres cargar los parámetros de configuración desde cualquier otra fuente en lugar de/aparte del archivo application.properties.

Solución

Quarkus utiliza la especificación Eclipse MicroProfile Configuration para implementar toda la lógica relativa a la configuración. La especificación ofrece la interfazo⁠r⁠g⁠.⁠e⁠c⁠l⁠i⁠p⁠s⁠e⁠.⁠m⁠i⁠c⁠r⁠o⁠p⁠r⁠o⁠f⁠i⁠l⁠e​.⁠c⁠o⁠n⁠f⁠i⁠g⁠.⁠s⁠p⁠i⁠.⁠C⁠o⁠n⁠f⁠i⁠g⁠S⁠o⁠u⁠r⁠c⁠eJava SPI para implementar una formapersonalizada de cargar las propiedades de configuración en lugar de/aparte de laproporcionada por defecto por Quarkus.

Por ejemplo, podrías cargar propiedades de configuración desde una base de datos, un archivo XML o una API REST.

Vamos a crear una sencilla fuente de configuración en memoria que obtenga las propiedades de configuración de Map pobladas en tiempo de instanciación. Crea una nueva clase llamada org.acme.quickstart.InMemoryConfigSource.java:

package org.acme.quickstart;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.microprofile.config.spi.ConfigSource;

public class InMemoryConfigSource implements ConfigSource {

    private Map<String, String> prop = new HashMap<>();

    public InMemoryConfigSource() { 1
        prop.put("greeting.color", "red");
    }

    @Override
    public int getOrdinal() { 2
        return 500;
    }

    @Override
    public Map<String, String> getProperties() { 3
        return prop;
    }

    @Override
    public String getValue(String propertyName) { 4
        return prop.get(propertyName);
    }

    @Override
    public String getName() { 5
        return "MemoryConfigSource";
    }

}
1

Rellena el mapa con una propiedad

2

Se utiliza para determinar la importancia de los valores; el ordinal más alto tiene prioridad sobre el ordinal de menor prioridad

3

Obtiene todas las propiedades como Map; en este caso es directo

4

Obtiene el valor de una sola propiedad

5

Devuelve el nombre de esta fuente de configuración

A continuación, tienes que registrarlo como un SPI Java. Crea la carpeta services en src/main/resources/META-INF. Después, crea un archivo dentro de services llamado org.eclipse.microprofile.config.spi.ConfigSource con el siguiente contenido:

org.acme.quickstart.InMemoryConfigSource

Por último, puedes modificar la clase org.acme.quickstart.GreetingResource.java para inyectar esta propiedad:

@ConfigProperty(name = "greeting.color") 1
String color;

@GET
@Path("/color")
@Produces(MediaType.TEXT_PLAIN)
public String color() {
    return color;
}
1

Inyecta el valor de la propiedad definida en la casilla InMemoryConfigSource

Y en una ventana de terminal haz una petición a /hello/color para ver que el mensaje de salida es el valor configurado en la fuente personalizada:

curl http://localhost:8080/hello/color

red

Debate

Cada ConfigSource tiene un ordinal especificado, que se utiliza para establecer la importancia de los valores tomados del ConfigSource en el caso de múltiples fuentes de configuración definidas para la misma aplicación. Un ConfigSource de ordinal superior se utiliza sobre un ConfigSource con un valor inferior. Utilizando como referencia los valores predeterminados de la siguiente lista, se utilizará una propiedad del sistema sobre todo, y se utilizará el archivo application. properties del directorio src/main/resources si no se encuentra ningún otro ConfigSources:

  • Propiedades del sistema a 400

  • Variables de entorno a 300

  • application.properties en el directorio config a 260

  • application.properties en el proyecto a 250

4.10 Crear conversores personalizados

Problema

Quieres implementar un conversor personalizado.

Solución

Puedes convertir una propiedad de String a cualquier tipo de objeto implementando el SPI de Java org.eclipse.microprofile.config.spi.Converter.

Quarkus utiliza la especificación Eclipse MicroProfile Configuration para implementar toda la lógica relativa a la configuración. La especificación ofrece la interfaz org.eclipse.microprofile.config.spi.Converter Java SPI para implementar la conversión de los valores de configuración a un tipo personalizado.

Por ejemplo, podrías transformar un valor porcentual (por ejemplo, 15%) en un tipo Percentage, envolviendo el porcentaje como tipo double.

Crea una nueva clase POJO org.acme.quickstart.Percentage.java:

package org.acme.quickstart;

public class Percentage {

    private double percentage;

    public Percentage(double percentage) {
        this.percentage = percentage;
    }

    public double getPercentage() {
        return percentage;
    }

}

Y luego crea una clase org.acme.quickstart.PercentageConverter.java que convierta la representación String en Percentage:

package org.acme.quickstart;

import javax.annotation.Priority;

import org.eclipse.microprofile.config.spi.Converter;

@Priority(300) 1
public class PercentageConverter implements Converter<Percentage> { 2

    @Override
    public Percentage convert(String value) {

        String numeric = value.substring(0, value.length() - 1);
        return new Percentage (Double.parseDouble(numeric) / 100);

    }

}
1

Establece la prioridad; en este caso concreto puede ser opcional

2

Tipo genérico que establece el tipo a convertir

A continuación, tienes que registrarlo como un SPI de Java. Crea la carpeta services en src/main/resources/META-INF. Después, crea un archivo dentro de la carpeta services llamadoorg.eclipse.microprofile.config.spi.Converter con el siguiente contenido:

org.acme.quickstart.PercentageConverter

A continuación, puedes modificar la clase org.acme.quickstart.GreetingResource.java para inyectar esta propiedad:

@ConfigProperty(name = "greeting.vat")
Percentage vat;

@GET
@Path("/vat")
@Produces(MediaType.TEXT_PLAIN)
public String vat() {
    return Double.toString(vat.getPercentage());
}

Por último, tendrás que añadir una nueva propiedad en el archivo application.properties de tu directorio src/main/resources:

greeting.vat = 21%

Y en una ventana de terminal, haz una petición a /hello/vat para ver que el mensaje de salida es la cuba transformada como doble:

curl http://localhost:8080/hello/vat

0.21

Debate

Por defecto, si no se encuentra ninguna anotación @Priority en un convertidor, se registra con una prioridad de 100. Los convertidores de Quarkus se registran con una prioridad de 200, por lo que si quieres sustituir un convertidor de Quarkus, debes utilizar un valor superior; si no necesitas sustituir un convertidor de Quarkus, el valor por defecto está perfectamente bien.

En la Receta 4.1 se muestra una lista de los convertidores del núcleo de Quarkus.

4.11 Agrupar valores de configuración

Problema

Quieres evitar establecer una y otra vez el prefijo común de una propiedad de configuración.

Solución

Puedes agrupar propiedades comunes (las que tienen el mismo prefijo) utilizando la anotación @⁠i⁠o​.⁠q⁠u⁠a⁠r⁠k⁠u⁠s⁠.⁠a⁠r⁠c⁠.⁠c⁠o⁠n⁠f⁠i⁠g⁠.⁠C⁠o⁠n⁠f⁠i⁠g⁠P⁠r⁠o⁠p⁠e⁠r⁠t⁠i⁠e⁠s.

Cuando crees propiedades de configuración ad hoc en tu aplicación, normalmente estas propiedades tendrán el mismo prefijo (es decir, greetings). Para inyectar todas estas propiedades, puedes utilizar la anotación @ConfigProperty (como se muestra en la Receta 4.1), opuedes utilizar la anotación io.quarkus.arc.config.ConfigProperties para agruparpropiedades.

Utilizando el archivo application.properties:

greeting.message=Hello World
greeting.suffix=!!, How are you???

vamos a implementar una clase que mapee las propiedades de configuración en objetos Java utilizando la anotación io.quarkus.arc.config.ConfigProperties. Crea una nueva clase org.acme.quickstart.GreetingConfiguration.java:

package org.acme.quickstart;

import java.util.List;
import java.util.Optional;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;

import io.quarkus.arc.config.ConfigProperties;

@ConfigProperties(prefix = "greeting") 1
public class GreetingConfiguration {

    public String message; 2
    public String suffix = "!"; 3
}
1

Establece esto como un POJO de configuración con un prefijo común

2

Mapea la propiedad greeting.message

3

El valor por defecto de greeting.suffix en caso de que no se establezca la propiedad

Una de las cosas importantes que hay que observar en el código anterior es que el atributo prefix no es obligatorio. Si no se establece, el prefijo que se utilizará vendrá determinado por el nombre de la clase (eliminando la parte del sufijo Configuration). En este caso, el atributo prefix podría autorresolverse a greeting.

Entonces puedes inyectar este POJO de configuración para empezar a consumir los valores de configuración.

Puedes modificar la clase org.acme.quickstart.GreetingResource.java para inyectar esta clase:

@Inject 1
GreetingConfiguration greetingConfiguration;

@GET
@Path("/configurations")
@Produces(MediaType.TEXT_PLAIN)
public String helloConfigurations() {
    return greetingConfiguration.message + greetingConfiguration.suffix;
}
1

La configuración se inyecta con la anotación CDI @Inject

Y en una ventana de terminal haz una petición a /hello/configurations para ver que los valores de configuración se rellenan dentro de Java, por ejemplo:

curl http://localhost:8080/hello/configurations

Hello World!!, How are you???

Como puedes ver ahora, no necesitas anotar cada campo utilizando @ConfigProperty-sólo tienes que aprovechar la definición de la clase para obtener el nombre de la propiedad o el valor por defecto.

Debate

Además, Quarkus admite la configuración de objetos anidados, de modo que también puedes asignar subcategorías utilizando clases internas.

Supongamos que añadimos una nueva propiedad llamada greeting.output.recipients enapplication.properties:

greeting.output.recipients=Ada,Alexandra

Podrías utilizar una clase interna para asignarla al objeto de configuración. Modifica la clase org.acme.quickstart.GreetingConfiguration.java. A continuación, añade una nueva clase interna que represente la subcategoría output y regístrala como campo:

public OutputConfiguration output; 1

public static class OutputConfiguration {
    public List<String> recipients;
}
1

El nombre de la subcategoría es el nombre del campo (output)

A continuación, puedes acceder al campo greetingConfiguration.output.recipients para obtener el valor.También puedes anotar los campos con anotaciones de validación de frijoles para validar en el momento del inicio que todos los valores de configuración son válidos. Si no lo son, la aplicación no se iniciará e indicará los errores de validación en el registro.

4.12 Validar los valores de configuración

Problema

Quieres validar que los valores de configuración son correctos.

Solución

Utiliza la especificación Bean Validation para validar que el valor de una propiedad es válido cuando se inyecta utilizando la anotación @ConfigProperty en una clase.

La especificación de Validación de Frijoles te permite establecer restricciones en los objetos mediante anotaciones. Quarkus integra la especificación de Configuración de Microperfiles de Eclipse con la especificación de Validación de Frijoles, de modo que puedes utilizarlas conjuntamente para validar que un valor de configuración cumple determinados criterios. Esta verificación se ejecuta en el momento del arranque, y si hay alguna infracción, se muestra un mensaje de error en la consola y se aborta el proceso de arranque.

Lo primero que tienes que hacer es registrar la dependencia Quarkus Bean Validation. Puedes hacerlo manualmente editando tu pom.xml o ejecutando el siguiente comando de Maven desde el directorio raíz del proyecto:

./mvnw quarkus:add-extension -Dextensions="quarkus-hibernate-validator"

Después, tendrás que crear un objeto de configuración, sobre el que aprendiste en la receta anterior. En el siguiente ejemplo, se establece una restricción en la propiedad de configuración greeting.repeat para que no se puedan establecer repeticiones fuera del rango 1-3 inclusive.

Para validar el rango de enteros, se utilizan las siguientes anotaciones de Validación de Frijoles: j⁠a⁠v⁠a⁠x​.⁠v⁠a⁠l⁠i⁠d⁠a⁠t⁠i⁠o⁠n⁠.⁠c⁠o⁠n⁠s⁠t⁠r⁠a⁠i⁠n⁠t⁠s⁠.⁠M⁠a⁠x y javax.validation.constraints.Min. Abre org.acme.quickstart.GreetingConfiguration.java y añade anotaciones de Validación de Frijoles:

@Min(1) 1
@Max(3) 2
public Integer repeat;
1

Valor mínimo aceptado

2

Valor máximo aceptado

Abre el archivo src/main/resources/application.properties y establece la propiedad de configuración greeting.repeat en 7:

greeting.repeat=7

Inicia la aplicación y verás un mensaje de error notificando que un valor de configuración infringe una de las restricciones definidas:

./mvnw compile quarkus:dev

Debate

En este ejemplo, has visto una breve introducción a la especificación de Validación de Frijoles, así como algunas anotaciones que puedes utilizar para validar campos. Sin embargo, Hibernate Validation y la implementación de Bean Validation utilizada admiten más restricciones, como @Digits, @Email, @NotNull, y @NotBlank.

Get Libro de cocina Quarkus now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.