web-dev-qa-db-fra.com

@Value non résolue lors de l'utilisation de l'annotation @PropertySource. Comment configurer PropertySourcesPlaceholderConfigurer?

J'ai la classe de configuration suivante:

@Configuration
@PropertySource(name = "props", value = "classpath:/app-config.properties")
@ComponentScan("service")
public class AppConfig {

et j'ai le service avec la propriété:

@Component 
public class SomeService {
    @Value("#{props['some.property']}") private String someProperty;

Je reçois une erreur lorsque je veux tester la classe de configuration AppConfig avec

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private Java.lang.String service.SomeService.someProperty; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'props' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' 

Le problème est documenté dans SPR-8539

mais de toute façon je ne peux pas comprendre comment configurer PropertySourcesPlaceholderConfigurer pour le faire fonctionner.

Modifier 1

Cette approche fonctionne bien avec la configuration XML

<util:properties id="props" location="classpath:/app-config.properties" />

mais je veux utiliser Java pour la configuration.

54
matus

Si vous utilisez @PropertySource, les propriétés doivent être récupérées avec:

@Autowired
Environment env;
// ...
String subject = env.getProperty("mail.subject");

Si vous voulez récupérer avec @Value ("$ {mail.subject}"), vous devez enregistrer le substitut prop par xml.

Raison: https://jira.springsource.org/browse/SPR-8539

30
laffuste

comme @cwash a dit;

@Configuration
@PropertySource("classpath:/test-config.properties")
public class TestConfig {

     @Value("${name}")
     public String name;


     //You need this
     @Bean
     public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
     }

}
119
baybora.oren

J'ai trouvé que la raison pour laquelle @value ne fonctionnait pas pour moi est que, @value requiert PropertySourcesPlaceholderConfigurer au lieu d'une PropertyPlaceholderConfigurer. J'ai apporté les mêmes modifications et cela a fonctionné pour moi. J'utilise la version printemps 4.0.3. J'ai configuré ceci en utilisant le code ci-dessous dans mon fichier de configuration.

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
   return new PropertySourcesPlaceholderConfigurer();
}
15

Vous n'avez pas besoin d'une méthode sur votre classe @Configuration qui retourne PropertySourcesPlaceholderConfigurer, annotée @Bean et est statique, pour enregistrer tout @PropertySource avec Spring? 

http://www.baeldung.com/2012/02/06/properties-with-spring/#Java

https://jira.springsource.org/browse/SPR-8539

11
cwash

J'ai eu le même problème. @PropertySource ne fonctionne pas bien avec @Value. Une solution rapide consiste à créer une configuration XML à laquelle vous vous référerez à partir de votre configuration Java Spring en utilisant @ImportResource comme d'habitude. Ce fichier de configuration XML inclut une seule entrée: <context:property-placeholder /> (bien sûr, avec la cérémonie d'espace de nom requise). Sans autre changement, @Value injectera des propriétés dans votre @Configuration pojo.

6
dimitrisli

Cela peut aussi être configuré en Java de cette façon

@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
    PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
    configurer.setIgnoreUnresolvablePlaceholders(true);
    configurer.setIgnoreResourceNotFound(true);
    return configurer;
}
5
Gowtham

Cela semble puissant compliqué, ne pouvez-vous pas simplement faire 

 <context:property-placeholder location="classpath:some.properties" ignore-unresolvable="true"/>

puis dans la référence du code:

@Value("${myProperty}")
private String myString;

@Value("${myProperty.two}")
private String myStringTwo;

où some.properties ressemble à quelque chose comme ça

myProperty = whatever
myProperty.two = something else\
that consists of multiline string

Pour la configuration basée sur Java, vous pouvez le faire

@Configuration
@PropertySource(value="classpath:some.properties")
public class SomeService {

Et puis juste injecter en utilisant @value comme avant

3
NimChimpsky

Le problème est le suivant: pour autant que je l’obtienne, <util: propertes id = "id" location = "loc" />, n’est qu’un raccourci pour 

<bean id="id" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <property name="location" value="loc"/>
</bean>

(voir documentation de util: properties ). Ainsi, lorsque vous utilisez util: properties, un bean autonome est créé.

@PropertySource, en revanche, comme le dit la documentation est un 

annotation fournissant un mécanisme commode et déclaratif pour ajout d'une PropertySource à l'environnement de Spring '.

(voir @PropertySource doc ). Donc, cela ne crée pas de haricot.

Alors "# {a ['quelque chose']}" est une expression SpEL (voir SpEL ), cela signifie "obtenir quelque chose de bean 'a'". Lorsque util: properties est utilisé, le bean existe et l'expression est significative, mais lorsque @PropertySource est utilisée, il n'y a pas de bean réel et l'expression n'a pas de sens.

Vous pouvez contourner ce problème en utilisant XML (ce qui est le meilleur moyen, je pense) ou en émettant vous-même un PropertiesFactoryBean, en le déclarant comme un @Bean normal.

2
Artem Shitov

Depuis Spring 4.3 RC2, utiliser PropertySourcesPlaceholderConfigurer ou <context:property-placeholder> n’est plus nécessaire. Nous pouvons utiliser directement @PropertySource avec @Value. Voir ceci Ticket cadre printemps

J'ai créé une application de test avec Spring 5.1.3.RELEASE . Le application.properties contient deux paires:

app.name=My application
app.version=1.1

La AppConfig charge les propriétés via @PropertySource

package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource(value = "application.properties", ignoreResourceNotFound = true)
public class AppConfig {

}

La Application injecte les propriétés via @Value et les utilise.

package com.zetcode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.zetcode")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

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

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

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);
        var app = ctx.getBean(Application.class);

        app.run();

        ctx.close();
    }

    public void run() {

        logger.info("Application name: {}", appName);
        logger.info("Application version: {}", appVersion);
    }
}

La sortie est:

$ mvn -q exec:Java
22:20:10.894 [com.zetcode.Application.main()] INFO  com.zetcode.Application - Application name: My application
22:20:10.894 [com.zetcode.Application.main()] INFO  com.zetcode.Application - Application version: 1.1
1
Jan Bodnar

Une autre chose qui peut se produire: assurez-vous que vos valeurs annotées @Value ne sont pas statiques.

0
davo