it-swarm.dev

Wartość @Value nie została rozwiązana podczas używania adnotacji @PropertySource. Jak skonfigurować PropertySourcesPlaceholderConfigurer?

Mam następującą klasę konfiguracji:

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

i mam usługę z własnością:

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

Otrzymuję błąd, gdy chcę przetestować klasę konfiguracji AppConfig za pomocą

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' 

Problem jest udokumentowany w SPR-8539

ale w każdym razie nie mogę dowiedzieć się, jak skonfigurować PropertySourcesPlaceholderConfigurer, aby to działało.

Edytuj 1

Podejście to działa dobrze w konfiguracji xml

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

ale chcę użyć Java do konfiguracji.

54
matus

Jeśli używasz @PropertySource, właściwości muszą zostać pobrane za pomocą:

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

Jeśli chcesz pobrać z @Value ("$ {mail.subject}"), musisz zarejestrować zastępczy prop przez xml.

Powód: https://jira.springsource.org/browse/SPR-8539

30
laffuste

jak powiedział @cwash;

@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

Znalazłem przyczynę, dla której @value nie działał dla mnie, jest @value wymaga PropertySourcesPlaceholderConfigurer zamiast PropertyPlaceholderConfigurer. Zrobiłem te same zmiany i zadziałało dla mnie, korzystam z wersji wiosna 4.0.3. Skonfigurowałem to używając poniższego kodu w moim pliku konfiguracyjnym.

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

Czy nie potrzebujesz metody na swojej klasie @Configuration, która zwraca właściwość PropertySourcesPlaceholderConfigurer, z adnotacją @Bean i jest statyczna, aby zarejestrować dowolną @PropertySource za pomocą Spring? 

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

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

11
cwash

Miałem ten sam problem. @PropertySource nie gra dobrze z @Value. Szybkim obejściem jest posiadanie konfiguracji XML, do której będziesz się odwoływać z Twojej konfiguracji Spring Java za pomocą @ImportResource jak zwykle, a plik konfiguracyjny XML będzie zawierał jeden wpis: <context:property-placeholder /> (oczywiście z potrzebną ceremonią przestrzeni nazw). Bez żadnej innej zmiany @Value wprowadzi właściwości w swoim @Configuration pojo.

6
dimitrisli

W ten sposób można to również skonfigurować w Javie

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

To wygląda na skomplikowane, nie możesz tego zrobić 

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

następnie w odsyłaczu do kodu:

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

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

gdzie some.properties wygląda mniej więcej tak

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

W przypadku konfiguracji opartej na Javie możesz to zrobić

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

A następnie po prostu wstrzyknij używając @value jak poprzednio

3
NimChimpsky

Chodzi o to, że o ile to rozumiem, <util: propertes id = "id" location = "loc" />, to tylko skrót dla 

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

(patrz dokumentacja util: properties ). Tak więc, gdy używasz właściwości util:, tworzona jest samodzielna fasola.

@PropertySource, z drugiej strony, jak mówi dokumentacja 

adnotacja zapewniająca wygodny i deklaratywny mechanizm dla dodanie PropertySource do Spring's Environment ”.

(patrz @PropertySource doc ). Więc nie tworzy żadnej fasoli.

Wtedy „# {a ['coś']}” jest wyrażeniem SpEL (patrz SpEL ), co oznacza „pobierz coś z bean„ a ””. Gdy używane są właściwości util:, komponent bean istnieje, a wyrażenie ma znaczenie, ale gdy użyto @PropertySource, nie ma rzeczywistego komponentu bean, a wyrażenie jest bez znaczenia.

Możesz obejść to, używając XML (jak sądzę, jest to najlepszy sposób) lub wydając polecenie PropertiesFactoryBean samodzielnie, deklarując go jako normalny @Bean.

2
Artem Shitov

Od wiosny 4.3 RC2 używający PropertySourcesPlaceholderConfigurer lub <context:property-placeholder> nie jest już potrzebny. Możemy użyć bezpośrednio @PropertySource z @Value. Zobacz Wiosenny bilet ramowy

Stworzyłem aplikację testową za pomocą Spring 5.1.3.RELEASE . Pole application.properties zawiera dwie pary:

app.name=My application
app.version=1.1

AppConfig ładuje właściwości przez @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 {

}

Application wstrzykuje właściwości przez @Value i używa ich.

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);
    }
}

Dane wyjściowe to:

$ 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

Inna rzecz, która może się zdarzyć: upewnij się, że wartości adnotacji @Value nie są statyczne.

0
davo