Contactez-nous

Accéder aux propriétés via `@Value`

Apprenez à utiliser l'annotation @Value dans Spring Boot pour injecter facilement des valeurs individuelles depuis vos fichiers de configuration (.properties, .yml) dans vos beans.

Injection simple : le rôle de @Value

L'une des manières les plus directes d'accéder aux valeurs définies dans vos fichiers de configuration (application.properties, application.yml, variables d'environnement, etc.) au sein de vos composants Spring (comme les @Component, @Service, @Controller) est d'utiliser l'annotation @Value. Cette annotation permet d'injecter la valeur d'une propriété spécifique directement dans un champ, un paramètre de méthode ou un paramètre de constructeur.

Elle est particulièrement utile lorsque vous avez besoin d'injecter une ou quelques valeurs de configuration simples et non nécessairement liées structurellement. C'est un mécanisme simple et efficace pour rendre vos beans configurables sans avoir à interagir directement avec l'objet Environment de Spring.

Syntaxe de base et exemples d'utilisation

La syntaxe la plus courante pour @Value utilise un placeholder sous la forme ${property.key}, où property.key est la clé de la propriété telle que définie dans votre fichier de configuration.

Supposons que votre fichier application.properties contienne :

app.name=Mon Application Incroyable
app.version=1.2.3
app.feature.enabled=true
app.max.connections=10

Ou l'équivalent en application.yml :

app:
  name: Mon Application Incroyable
  version: 1.2.3
  feature:
    enabled: true
  max:
    connections: 10

Vous pouvez injecter ces valeurs dans un bean comme ceci :

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AppConfigPrinter {

    @Value("${app.name}")
    private String applicationName;

    @Value("${app.version}")
    private String applicationVersion;

    @Value("${app.feature.enabled}")
    private boolean featureEnabled;

    @Value("${app.max.connections}")
    private int maxConnections;

    public void printConfig() {
        System.out.println("Nom de l'application: " + applicationName);
        System.out.println("Version: " + applicationVersion);
        System.out.println("Fonctionnalité activée: " + featureEnabled);
        System.out.println("Connexions max: " + maxConnections);
    }
}

Spring Boot lira les valeurs correspondantes depuis les sources de configuration et les injectera dans les champs annotés lors de la création du bean AppConfigPrinter. Notez que Spring gère automatiquement la conversion de type : la chaîne "10" du fichier de propriétés est convertie en entier (int), et "true" en booléen (boolean).

Gérer les valeurs par défaut

Que se passe-t-il si une propriété référencée par @Value n'est définie dans aucune source de configuration (ni fichier, ni variable d'environnement, etc.) ? Par défaut, Spring lèvera une exception au démarrage de l'application (généralement une IllegalArgumentException indiquant que le placeholder n'a pas pu être résolu), car il ne peut pas injecter de valeur.

Pour éviter cela et fournir une valeur de secours, vous pouvez spécifier une valeur par défaut directement dans l'annotation @Value en utilisant le caractère deux-points (:) à l'intérieur du placeholder :

@Component
public class AnotherComponent {

    // Si 'server.default.name' n'est pas trouvé, utilise "ServeurParDefaut"
    @Value("${server.default.name:ServeurParDefaut}")
    private String serverName;

    // Si 'server.timeout.ms' n'est pas trouvé, utilise 5000
    @Value("${server.timeout.ms:5000}")
    private int timeoutMillis;

    public void showDefaults() {
        System.out.println("Nom du serveur: " + serverName);
        System.out.println("Timeout (ms): " + timeoutMillis);
    }
}

Cette fonctionnalité est très pratique pour rendre votre application plus robuste et pour définir des comportements par défaut sensés lorsque certaines configurations ne sont pas explicitement fournies.

Utilisation de Spring Expression Language (SpEL)

L'annotation @Value est encore plus puissante car elle supporte Spring Expression Language (SpEL). Au lieu d'utiliser la syntaxe ${...} qui recherche directement une clé de propriété, vous pouvez utiliser la syntaxe #{...} pour évaluer des expressions SpEL.

Cela ouvre de nombreuses possibilités :

  • Accéder aux propriétés système Java :
    @Value("#{systemProperties['java.io.tmpdir']}")
    private String tempDir;
  • Accéder aux propriétés d'autres beans :
    @Value("#{autreBean.getSomeProperty()}")
    private String otherBeanProperty;
  • Effectuer des opérations ou appeler des méthodes statiques :
    @Value("#{ T(java.lang.Math).random() * 100.0 }")
    private double randomNumber;
    
    @Value("#{ T(java.util.UUID).randomUUID().toString() }")
    private String randomUuid;
  • Combiner placeholders et SpEL : Vous pouvez même utiliser des placeholders ${...} à l'intérieur d'expressions SpEL #{...}, ou inversement (bien que moins courant). Par exemple, pour combiner deux propriétés :
    @Value("Configuration pour ${app.name:Application par Défaut}")
    private String configTitle;

L'utilisation de SpEL offre une grande flexibilité mais peut aussi rendre la configuration plus complexe à comprendre. Il est souvent utilisé pour des cas d'injection plus dynamiques ou pour accéder à des informations qui ne sont pas directement dans les fichiers de propriétés standards.

Points d'injection et limitations

Comme mentionné, @Value peut être appliquée à différents endroits :

  • Champs (Fields) : Le cas le plus fréquent, montré dans les exemples précédents.
  • Paramètres de constructeur : Pour injecter des valeurs lors de la construction de l'objet.
  • Paramètres de méthode : Moins courant pour l'injection de propriétés simples, mais possible (par exemple, sur des méthodes de configuration @Bean ou des setters).
@Component
public class ConstructorInjection {
    private final String message;

    public ConstructorInjection(@Value("${welcome.message:Bonjour !}") String message) {
        this.message = message;
        System.out.println("Message injecté: " + message);
    }
}

Bien que @Value soit pratique pour injecter des valeurs individuelles, elle présente quelques limitations :

  • Elle n'est pas idéale pour injecter un grand nombre de propriétés, surtout si elles sont liées logiquement (par exemple, toutes les propriétés d'une connexion à une base de données). Le code peut devenir verbeux.
  • La validation des propriétés injectées n'est pas directement intégrée (contrairement à @ConfigurationProperties).
  • Elle lie directement le composant à des clés de propriété spécifiques, ce qui peut être moins flexible si la structure de la configuration change.

Pour ces raisons, lorsque vous avez affaire à un ensemble de propriétés de configuration structurées et liées, l'approche recommandée est souvent d'utiliser l'annotation @ConfigurationProperties, qui permet de lier ces propriétés à un objet Java dédié (POJO) de manière type-safe.