web-dev-qa-db-fra.com

Le fichier Spring @Configuration avec le bean PropertyPlaceholderConfigurer ne résout pas l'annotation @Value

J'ai le fichier de configuration suivant:

@Configuration
public class PropertyPlaceholderConfigurerConfig {

    @Value("${property:defaultValue}")
    private String property;

    @Bean
    public static PropertyPlaceholderConfigurer ppc() throws IOException {
        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
        ppc.setLocations(new ClassPathResource("properties/" + property + ".properties"));
        ppc.setIgnoreUnresolvablePlaceholders(true);
        return ppc;
    }
}

J'exécute mon application en suivant VM option:

-Dproperty=propertyValue

J'aimerais donc que mon application charge un fichier de propriétés spécifique au démarrage. Mais pour une raison quelconque à ce stade @Value les annotations ne sont pas traitées et la propriété est null. D'un autre côté, si j'ai PropertyPlaceholderConfigurer configuré via un fichier xml - tout fonctionne parfaitement comme prévu. Exemple de fichier XML:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="ignoreResourceNotFound" value="true"/>
    <property name="location">
        <value>classpath:properties/${property:defaultValue}.properties</value>
    </property>
</bean>

Si j'essaie d'injecter la valeur d'une propriété dans un autre fichier de configuration Spring - elle est correctement injectée. Si je déplace ma création de bean PropertyPlaceholderConfigurer vers ce fichier de configuration, la valeur du champ est de nouveau nulle.

Pour contourner ce problème, j'utilise cette ligne de code:

System.getProperties().getProperty("property", "defaultValue")

Ce qui fonctionne également, mais j'aimerais savoir pourquoi un tel comportement se produit et peut-être qu'il est possible de le réécrire d'une autre manière mais sans xml?

19
Oleksii Duzhyi

Depuis le printemps JavaDoc :

Afin de résoudre les espaces réservés $ {...} dans les définitions ou les annotations @Value à l'aide des propriétés d'un PropertySource, il faut enregistrer un PropertySourcesPlaceholderConfigurer. Cela se produit automatiquement lors de l'utilisation en XML, mais doit être explicitement enregistré à l'aide d'une méthode @Bean statique lors de l'utilisation des classes @Configuration. Voir la section "Travailler avec des valeurs externalisées" de javadoc de @ Configuration et "une note sur les méthodes @Bean retournant BeanFactoryPostProcessor" de javadoc de @ Bean pour plus de détails et des exemples.

Par conséquent, vous essayez d'utiliser un espace réservé dans le bloc de code requis pour activer le traitement des espaces réservés.

Comme @ M.Deinum l'a mentionné, vous devez utiliser un PropertySource (implémentation par défaut ou personnalisée).

L'exemple ci-dessous montre comment utiliser des propriétés dans une annotation PropertySource ainsi que comment injecter des propriétés depuis PropertySource dans un champ.

@Configuration
@PropertySource(
          value={"classpath:properties/${property:defaultValue}.properties"},
          ignoreResourceNotFound = true)
public class ConfigExample {

    @Value("${propertyNameFromFile:defaultValue}")
    String propertyToBeInjected;

    /**
     * Property placeholder configurer needed to process @Value annotations
     */
     @Bean
     public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
     }
}
38
proactive-e

Pour toutes les autres pauvres âmes qui ne pouvaient pas faire fonctionner cela dans certaines classes de configuration quand elles travaillent dans d'autres:

Regardez pour voir quels autres beans vous avez dans cette classe et si l'un d'eux est instancié tôt dans ApplicationContext. Un ConversionService en est un exemple. Cela instancierait la classe Configuration avant que ce qui est requis ne soit enregistré, ce qui ne provoquerait aucune injection de propriété.

J'ai résolu ce problème en déplaçant le ConversionService vers une autre classe de configuration que j'ai importée.

6
George Hilios

Si vous exécutez votre application en utilisant VM et que vous souhaitez ensuite accéder à cette option dans votre application, vous devez le faire légèrement différemment:

@Value("#{systemProperties.property}")
private String property;

Votre PropertyPlaceholderConfigurer ne connaît pas les propriétés du système, notez également que vous accédez aux propriétés à l'aide de $ - qui fait référence aux espaces réservés et # fait référence aux beans, où systemProperties est un bean.

2
Paulius Matulionis