Java 带有PropertyPlaceholderConfigurer bean的Spring@Configuration文件不';t解析@Value注释

Java 带有PropertyPlaceholderConfigurer bean的Spring@Configuration文件不';t解析@Value注释,java,xml,spring,configuration,Java,Xml,Spring,Configuration,我有以下配置文件: @Configuration public class PropertyPlaceholderConfigurerConfig { @Value("${property:defaultValue}") private String property; @Bean public static PropertyPlaceholderConfigurer ppc() throws IOException { PropertyPla

我有以下配置文件:

@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;
    }
}
我使用以下VM选项运行应用程序:

-Dproperty=propertyValue
所以我希望我的应用程序在启动时加载特定的属性文件。但由于某些原因,在这个阶段,
@Value
注释未被处理,属性为
null
。另一方面,如果我通过xml文件配置了
propertyplaceholderconfigure
,那么一切都会像预期的那样完美。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>

这也是可行的,但我想知道为什么会发生这种行为,也许可以用其他方式重写它,但不使用xml?

如果您使用VM选项运行应用程序,然后希望在应用程序中访问该选项,那么您必须做得稍有不同:

@Value("#{systemProperties.property}")
private String property;
您的PropertyPlaceHolderConfiguration不知道系统属性,还请注意,您正在使用
$
-访问属性,它指的是占位符,
#
指的是bean,其中
systemProperties
是bean。

来自Spring:

为了使用PropertySource中的属性解析定义或@Value注释中的${…}占位符,必须注册PropertySourcesPlaceholderConfigurer。这在XML中使用时会自动发生,但在使用@Configuration类时必须使用静态@Bean方法显式注册。有关详细信息和示例,请参阅@Configuration的javadoc的“使用外部化值”部分和@Bean的javadoc的“关于BeanFactoryPostProcessor返回@Bean方法的说明”

因此,您试图在启用占位符处理所需的代码块中使用占位符

如@M.Deinum所述,您应该使用PropertySource(默认或自定义实现)

下面的示例显示如何在PropertySource注释中使用属性,以及如何将PropertySource中的属性注入字段

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

对于其他在某些配置类中无法实现此功能而在其他配置类中无法实现此功能的可怜人:

查看该类中还有哪些bean,以及它们中是否有任何bean在ApplicationContext的早期被实例化。ConversionService就是一个例子。这将在注册所需内容之前实例化配置类,从而不进行属性注入


我通过将ConversionService移动到我导入的另一个配置类来解决这个问题。

首先,我强烈建议使用
PropertySourceSplaceHolderConfigure
,并在类上使用
@PropertySource
。其次,bean需要是静态的,对我来说非常适合,但是如果我有
propertySourceSplaceHolderConfigure
的自定义实现怎么办?为什么您需要自定义实现。@M.Deinum从ZooKeeper加载属性例如,您不需要自定义实现,因为您需要自定义
PropertySource
,不幸的是,它在我的配置中不起作用PropertyPlaceholderConfigurer bean创建,但可以在任何其他配置文件中工作如果我想在bean创建方法中添加其他属性怎么办?我正在手动加载我的yaml文件属性,并希望将其添加到PropertySources中我认为处理@Value注释所需的属性占位符配置器不再正确,因为Spring 4.3和
PropertySonfiguer()
可以从示例中删除?另一种可能是使用构造函数注入,如下所述:
@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();
     }
}