Validar las propiedades de configuración de Spring Boot al iniciar la aplicación

Escrito por el .
java planeta-codigo
Enlace permanente Comentarios

Spring permite realizar validaciones sobre las propiedades de configuración antes de iniciar la aplicación, esto permite evitar errores en tiempo de ejecución más difíciles de depurar ya que la excepción que se origine quizá sea difícil de asociar a que el valor una variable de configuración es incorrecta, por ejemplo, que una variable de configuración no tiene valor y si fuese una contraseña de base de datos originar un fallo de conexión a la base de datos o que un servicio REST devolviese un error 403 por no proporcionar la credencial. Con las mismas anotaciones de validación sobre las propiedades de configuración del paquete javax.validation que se utilizan para validar beans de Java se pueden utilizar para validar los valores de configuración de Spring.

Java

Spring

Al recibir datos los programas tienen varias opciones. Una es ser estricto, validar los datos y en caso de que no sean válidos emitir un mensaje y devolver un error impidiendo continuar. Otra opción es ser flexible para validar los datos y en caso de que sean incorrectos tomar valores por defecto para al menos realizar la tarea aunque sea en un modo degradado. La opción final es no validar los datos y dar por supuesto que son correctos.

No validar los datos tiene varios problemas que se pueden manifestar en la aplicación de diferentes formas, fallando en el procesado de los datos quizá habiendo realizado parte de la tarea, ocasionando algún fallo de seguridad o generando resultados incorrectos o inconsistencias en otros datos. Cualquiera de estas formas de errores son manifestaciones que pueden tener como causa unos datos no válidos de entrada, errores cuya causa raíz pueden no ser fácilmente identificable al intentar depurar el programa y que suelen requerir muchas horas de investigación. Por ello validar los datos es una buena práctica al crear aplicaciones, sobre todo validar datos que provienen de fuentes no confiables como información introducida por el usuario o programas externos.

La configuración de una aplicación es otra forma de datos que un programa utiliza, en este caso para variar su comportamiento en tiempo de ejecución sin necesidad de recompilar la aplicación o generar un nuevo artefacto binario para su ejecución. Sobre las variables de configuración también es posible realizar validaciones y en caso de que las variables de configuración sean incorrectas fallar de forma temprana en vez de fallar más tarde cuando se realiza una acción.

Cómo validar propiedades de configuración

La configuración de una aplicación son simplemente variables a la que se les da un nombre y a través del cual se recupera un valor. El programa no tiene hardcodeado en el código el valor e incluyéndose en un archivo de configuración permite cambiarlo sin cambiar el código.

Por ejemplo, si un programa necesita conectarse a una base de datos seguramente necesite unas credenciales compuestas por el host del servidor de base de datos, un usuario y una contraseña de conexión. Estos datos de configuración para el programa son requeridos ya que quizá sin poder conectarse a la base de datos va a fallar. Otros datos quizá deban ser numéricos, no vacíos, deban tener un valor mínimo o máximo o deban cumplir una expresión regular.

El framework Spring proporciona varias funcionalidades útiles para las aplicaciones relacionadas con la configuración desde un mecanismo muy flexible de proporcionar los valores de las propiedades de diferentes fuentes hasta un servidor de configuración centralizada. Otra de sus funcionalidades es precisamente validar las propiedades de configuración a través de anotaciones.

Aunque no sean validaciones complejas son útiles ya que normalmente las variables las crean los desarrolladores pero al desplegar la aplicación o tener que cambiar algún valor puede que lo realicen personas con el rol de sistemas que quizá no conozcan tan en detalle las variables de configuración existentes y sus reglas de validación. Al añadir las validaciones si alguna falla se obtiene un mensaje de error bastante descriptivo de cual es el problema de configuración.

Ejemplo de código

Una forma de recuperar los valores de configuración en una aplicación de Spring es trasladando los valores de los archivos de configuración a clases Java que contengan sus valores y sean fácilmente usables desde el lenguaje Java. Es en estas clases Java donde se colocan las anotaciones de validación.

Las anotaciones que se pueden utilizar son las anotaciones del paquete javax.validation, realmente son las mismas anotaciones para realizar validaciones sobre cualquier otro tipo de objeto Java, en este caso simplemente son clases con propiedades de configuración.

Este es un ejemplo de archivo de configuración de una aplicación en la que hay una serie de propiedades. Dependiendo del entorno y de los valores proporcionados en tiempo de ejecución a través de este archivo de configuración, propiedades del sistema o variables de entorno las propiedades tendrán unos valores u otros y algunos valores como las contraseñas por motivos de seguridad es preferible no incluirlos en los archivos de configuración del código fuente para no compartirlas en el sistema de control de versiones.

1
2
3
4
5
6
7
8
spring:
  profiles:
    default: "local"

app:
  numeric: 5
  regexp: "A0000"
  password:
application-2.yaml

Dado que algunas propiedades es necesario proporcionarle en tiempo de ejecución la aplicación como medida de precaución valida que los valores de las propiedades son válidas. Esta es una clase que tiene el objetivo de cargar y proporcionar acceso a los valores de configuración.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package io.github.picodotdev.blogbitix.springbootconfigvalidated;

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

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;

@Configuration
@ConfigurationProperties(prefix = "app")
@Validated
public class AppConfiguration {

    @Min(3)
    @Max(10)
    private Integer numeric;
    @Pattern(regexp = "[A-Z]\\d{3,}")
    private String regexp;
    @NotBlank
    private String password;

    public Integer getNumeric() {
        return numeric;
    }

    public void setNumeric(Integer numeric) {
        this.numeric = numeric;
    }

    public String getRegexp() {
        return regexp;
    }

    public void setRegexp(String regexp) {
        this.regexp = regexp;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
AppConfiguration.java

La clase al estar anotada con la anotación @Configuration de Spring la identifica como una clase de configuración y con el atributo prefix Spring carga los valores de las variables de configuración cuyos nombres coinciden con los nombres de las propiedades. La clase incluye también la anotación @Validated que indica que debe ser validada con las anotaciones de validación que incluya. Finalmente, las propiedades que necesitan validaciones se anotan con la anotación correspondiente para hacer la propiedad requerida u otro tipo de validación sobre su valor.

Realizando validaciones sobre los valores de las propiedades de configuración si la aplicación se inicia y una o varias propiedades no cumplen una validación, la aplicación en vez de continuar finaliza inmediatamente con un mensaje de error que indica que una propiedad no cumple las validaciones.

1
2
3
4
5
6
7
8
spring:
  profiles:
    default: "local"

app:
  numeric: 0
  regexp: "0000"
  password:
application-1.yaml
1
2
$ ./gradlew run

gradlew-run-1.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'app' to io.github.picodotdev.blogbitix.springbootconfigvalidated.AppConfiguration$$EnhancerBySpringCGLIB$$ae0ed48d failed:

    Property: app.regexp
    Value: 0000
    Origin: class path resource [application.yml] - 7:11
    Reason: debe coincidir con "[A-Z]\d{3,}"

    Property: app.password
    Value: 
    Origin: class path resource [application.yml] - 8:12
    Reason: no debe estar vacío

    Property: app.numeric
    Value: 0
    Origin: class path resource [application.yml] - 6:12
    Reason: debe ser mayor que o igual a 3


Action:

Update your application's configuration
System.out-1

Cambiando el comando de inicio para proporcionar el valor requerido y que las otras propiedades sean válidas la aplicación se inicia correctamente.

1
2
3
4
5
6
7
8
spring:
  profiles:
    default: "local"

app:
  numeric: 5
  regexp: "A0000"
  password:
application-2.yaml
1
2
$ APP_PASSWORD="java" ./gradlew run

gradlew-run-2.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
> Task :app:run

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.2)

2022-02-03 19:11:28.623  INFO 11424 --- [           main] i.g.p.b.springbootconfigvalidated.Main   : Starting Main using Java 17.0.1 on archlinux with PID 11424 (/home/picodotdev/Documentos/Software/personal/blog-ejemplos/SpringBootConfigValidated/app/build/classes/java/main started by picodotdev in /home/picodotdev/Documentos/Software/personal/blog-ejemplos/SpringBootConfigValidated/app)
2022-02-03 19:11:28.626  INFO 11424 --- [           main] i.g.p.b.springbootconfigvalidated.Main   : No active profile set, falling back to default profiles: local
2022-02-03 19:11:29.164  INFO 11424 --- [           main] i.g.p.b.springbootconfigvalidated.Main   : Started Main in 0.887 seconds (JVM running for 1.141)
System.out-2
Terminal

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:
./gradlew run


Comparte el artículo: