La anotación @Value en Spring

@Value es una anotación de Java utilizada en el nivel de campo o método/constructor. Se usa comúnmente para inyectar valores en variables de configuración. En este artículo, cubriremos las muchas formas en que puede usar la anotación @Value.

Introducción

El enfoque principal de este artículo es ayudarlo a comprender cómo Spring's [@Valor](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/ factory/annotation/Value.html) funciona la anotación.

@Value es una anotación de Java que se utiliza en el nivel de parámetro de campo o método/constructor e indica un valor predeterminado para el argumento afectado. Se usa comúnmente para inyectar valores en variables de configuración, que mostraremos y explicaremos en la siguiente parte del artículo.

Tarea básica

Para los ejemplos más sencillos, asignaremos valores a tres campos diferentes usando la anotación @Value dándoles valores explícitos:

1
2
3
4
5
6
7
8
@Value("John")
private String trainee;

@Value("100")
private int hoursOfCode;

@Value("true")
private boolean passedAssesmentTest;

Es muy importante tener en cuenta que el argumento pasado a la anotación @Value solo puede ser una String. Spring convertirá el valor al tipo especificado y la asignación se realizará sin problemas, incluso si estamos pasando valores String a variables int o boolean.

Entorno primaveral

Inyectar valores de archivos de propiedades con la ayuda de la anotación @Value es probablemente el caso de uso más utilizado en aplicaciones de la vida real.

Usaremos el archivo de propiedades predeterminado para Spring Boot - application.properties, donde podemos definir variables a las que podemos acceder después:

1
2
3
car.brand=Audi
car.color=Red
car.power=150
1
2
3
4
5
6
7
8
@Value("${car.brand")
private String brand;

@Value("${car.color}")
private String color;

@Value("${car.power}")
private int power;

En este ejemplo, los valores de las variables se leen del archivo application.properties y se les asignan durante la creación del bean.

La mayoría de las veces, usaríamos este enfoque para inyectar valores de configuración del archivo application.properties en beans.

Valor predeterminado {#valor predeterminado}

Los valores predeterminados se utilizan como "alternativa" si la propiedad que deseamos inyectar no está definida o falta:

1
2
@Value("${car.type:Sedan}")
private String type;

En el ejemplo anterior, debido a que no tenemos ninguna propiedad car.type en application.properties, Spring asignará Sedan a la variable type como valor predeterminado.

Si la propiedad car.type se inserta en el archivo de propiedades, se usará el nuevo valor en su lugar.

Variables del sistema

También podemos acceder a las variables del sistema que la aplicación Spring almacena como propiedades al inicio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Value("${user.name}")
// Or
@Value("${username}")
private String userName;

@Value("${number.of.processors}")
// Or
@Value("${number_of_processors}")
private int numberOfProcessors;

@Value("${java.home}")
private String java;

Las variables se pueden llamar con diferentes convenciones de nomenclatura: Spring nos busca y asigna el valor correcto.

Valor de método global {#valor de método global}

Debido a que @Value es procesado por la clase BeanPostProcessor, se invocará cuando Spring esté construyendo el contexto de Spring instanciando archivos de configuración y beans.

Esto significa que al tener @Value en un método, todos los argumentos se asignarán con el valor proporcionado a la anotación:

1
2
3
4
5
@Value("${car.brand}")
public CarData setCarData(String color, String brand) {
    carData.setCarColor(color);
    carData.setCarBrand(brand);
}

Si estamos imprimiendo carData.getCarColor() y carData.getCarBrand() obtendremos el valor de car.brand en ambas ocasiones, porque como dijimos, todos los argumentos se mapearán con el valor proporcionado.

Valor del método del parámetro

Podemos arreglar esto usando @Value directamente en el parámetro del método:

1
2
3
4
5
@Value("${car.brand}")
public CarData setCarData(@Value("${car.color}") String color, String brand) {
    carData.setCarColor(color);
    carData.setCarBrand(brand);
}

Ahora, si estamos imprimiendo los valores del objeto carData, el campo de color tendrá el valor car.color, porque proporcionamos el valor al parámetro del método en sí.

Spring Expression Language (SpEL)

El Lenguaje de expresión de Spring (SpEL) es un lenguaje de expresión que sirve como base para la evaluación de expresiones dentro del portafolio de Spring.

Básicamente, cuando usamos SpEL junto con la anotación @Value, solo estamos cambiando la forma en que le decimos a Spring lo que necesitamos. Miremos más de cerca:

1
2
@Value("#{systemProperties['user.name']}")
private String userName;

Así es como inyectaría una propiedad específica del sistema. Por otro lado, podríamos inyectar todas las propiedades mediante:

1
2
@Value("#{systemProperties}")
private Map<String, String> properties;

Ahora sabemos que podemos usar la anotación @Value para métodos como valor global o como valor de parámetro.

Dado que los constructores son esencialmente métodos, también podemos usar la anotación en los constructores:

1
2
3
4
public Driver(@Value("#{systemProperties['user.name']}") String name, String location) {
    this.name = name;
    this.location = location;
}

Inyectando en Maps

Con SpEL, podemos hacer otras cosas bastante interesantes cuando se combina con la anotación @Value. Por ejemplo, hagamos un ‘mapa’ que represente los pasatiempos ‘interiores’ y ’exteriores’ de un estudiante. Cada uno de estos puede tener múltiples valores:

1
student.hobbies={indoor: 'reading, drawing', outdoor: 'fishing, hiking, bushcraft'}

Ahora, para inyectar esto, necesitaremos un Map<String, List<String>>:

1
2
@Value("#{${student.hobbies}}")
private Map<String, List<String>> hobbies;

Inyectando en listas

Si una propiedad tiene valores separados por comas, como una simple lista de libros, podemos usar SpEL para interpretarla y transformarla en una lista:

1
student.booksRead=Harry Potter,The Hobbit,Game of Thrones

Usando el método split() y dividiendo cada coma (,), podemos inyectar estos valores en una lista:

1
2
@Value("#{'${student.booksRead}'.split(',')}")
private List<String> booksRead;

Conclusión

Tan pronto como termina trabajando en una aplicación real, se da cuenta de que la configuración es un tema importante y si está utilizando Spring. Hay una gran posibilidad de que ya estés usando o tendrás que usar la anotación @Value extensamente.

Comprender esta funcionalidad básica es muy importante porque si no lo hace, podría terminar usándolo totalmente mal.

También debemos ser conscientes de que no todo lo que parece simple también es muy bueno para soluciones a largo plazo. Por ejemplo, solo deberíamos usar @Value en componentes/servicios encapsulados (podemos llamarlos servicios de configuración).

De esta forma, tendremos todas nuestras configuraciones en un solo lugar, y ese componente solo tendrá la responsabilidad de cargarlas y proporcionarlas a otros componentes. entes.