使用@PropertySource注释时@Value未解析。如何配置PropertySourcesPlaceholderConfigurer?

时间:2012-12-05 16:37:50

标签: spring configuration

我有以下配置类:

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

我有财产服务:

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

当我想用

测试AppConfig配置类时,我收到错误
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' 

问题记录在in SPR-8539

但无论如何我无法弄清楚如何配置 PropertySourcesPlaceholderConfigurer 以使其正常工作。

编辑1

这种方法适用于xml配置

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

但我想使用java进行配置。

11 个答案:

答案 0 :(得分:120)

正如@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();
     }

}

答案 1 :(得分:30)

如果使用@PropertySource,则必须使用以下命令检索属性:

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

如果要使用@Value(“$ {mail.subject}”)进行检索,则必须通过xml注册prop占位符。

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

答案 2 :(得分:16)

我发现@value对我不起作用的原因是@value需要PropertySourcesPlaceholderConfigurer而不是PropertyPlaceholderConfigurer。我做了相同的更改,它对我有用,我使用的是Spring 4.0.3版本。我使用配置文件中的以下代码配置了它。

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

答案 3 :(得分:11)

你的@Configuration类上是否需要一个方法来返回PropertySourcesPlaceholderConfigurer,带注释的@Bean并且是静态的,用Spring注册任何@PropertySource?

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

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

答案 4 :(得分:6)

我遇到了同样的问题。 @PropertySource@Value的效果不佳。一个快速的解决方法是拥有一个XML配置,您可以像往常一样使用@ImportResource从Spring Java配置中引用它,并且XML配置文件将包含一个条目:<context:property-placeholder />(当然使用需要命名空间仪式)。没有任何其他更改@Value将在@Configuration pojo中注入属性。

答案 5 :(得分:4)

这也可以用java这种方式配置

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

答案 6 :(得分:3)

看起来很复杂,你不能这么做吗

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

然后在代码参考中:

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

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

其中some.properties看起来像这样

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

对于基于java的配置,您可以执行此操作

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

然后像以前一样使用@value注入

答案 7 :(得分:2)

事情是:据我所知,&lt; util:propertes id =“id”location =“loc”/&gt;,只是

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

(见documentation of util:properties)。因此,当您使用util:properties时,会创建一个独立的bean。

另一方面,

@PropertySource,正如文档所说的那样

  

注释提供方便和声明的机制   将一个PropertySource添加到Spring的环境中。

(见@PropertySource doc)。所以它不会创建任何bean。

然后“#{a ['something']}”是一个SpEL表达式(参见SpEL),这意味着“从 bean '得到一些'a'”。当使用util:属性时,bean存在且表达式有意义,但是当使用@PropertySource时,没有实际的bean,表达式毫无意义。

您可以使用XML(我认为这是最好的方法)或通过自己发布一个PropertiesFactoryBean来解决这个问题,并将其声明为普通的@Bean。

答案 8 :(得分:1)

因为不再需要使用PropertySourcesPlaceholderConfigurer<context:property-placeholder>的Spring 4.3 RC2。我们可以将@PropertySource@Value直接使用。看到这个Spring framework ticket

我已经用Spring 5.1.3.RELEASE创建了一个测试应用程序。 application.properties包含两对:

app.name=My application
app.version=1.1

AppConfig通过@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通过@Value注入属性并使用它们。

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

输出为:

$ 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

答案 9 :(得分:0)

可能发生的另一件事:确保您的@Value注释值不是静态的。

答案 10 :(得分:0)

在我的情况下,property-on =“ bean1”位于property-placeholder内导致了此问题。我删除了该依赖关系,并使用@PostConstruct实现了相同的原始功能,并且也能够读取新值。