Java 带有 PropertyPlaceholderConfigurer bean 的 Spring @Configuration 文件无法解析 @Value 注释

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33344895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:35:13  来源:igfitidea点击:

Spring @Configuration file with PropertyPlaceholderConfigurer bean doesn't resolve @Value annotation

javaxmlspringconfiguration

提问by Oleksii Duzhyi

I have following configuration file:

我有以下配置文件:

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

I run my application with following VM option:

我使用以下 VM 选项运行我的应用程序:

-Dproperty=propertyValue

So I'd like my application to load specific property file on startup. But for some reason at this stage @Valueannotations are not processed and property is null. On the other hand if I have PropertyPlaceholderConfigurerconfigured via xml file - everything works perfectly as expected. Xml file example:

所以我希望我的应用程序在启动时加载特定的属性文件。但出于某种原因,在这个阶段@Value注释没有被处理,属性是null. 另一方面,如果我PropertyPlaceholderConfigurer通过 xml 文件进行了配置 - 一切都按预期完美运行。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>

If I try to to inject property value in another Spring configuration file - it is properly injected. If I move my PropertyPlaceholderConfigurerbean creation to that configuration file - field value is null again.

如果我尝试在另一个 Spring 配置文件中注入属性值 - 它被正确注入。如果我将PropertyPlaceholderConfigurerbean 创建移动到该配置文件 - 字段值再次为空。

As workaround, I use this line of code:

作为解决方法,我使用这行代码:

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

Which is also works, but I'd like to know why such behavior is occurs and maybe it is possible to rewrite it in other way but without xml?

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

采纳答案by proactive-e

From Spring JavaDoc:

从 Spring JavaDoc

In order to resolve ${...} placeholders in definitions or @Value annotations using properties from a PropertySource, one must register a PropertySourcesPlaceholderConfigurer. This happens automatically when using in XML, but must be explicitly registered using a static @Bean method when using @Configuration classes. See the "Working with externalized values" section of @Configuration's javadoc and "a note on BeanFactoryPostProcessor-returning @Bean methods" of @Bean's javadoc for details and examples.

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

So, you are trying to use a placeholder in the code block required to enable placeholder processing.

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

As @M.Deinum mentioned, you should use a PropertySource (default or custom implementation).

正如@M.Deinum 提到的,您应该使用 PropertySource(默认或自定义实现)。

Example below shows how to use properties in a PropertySource annotation as well as how to inject properties from the PropertySource in a field.

下面的示例显示了如何在 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();
     }
}

回答by Paulius Matulionis

If you run your application using VM option and then want to access that option in your application you have to do it slightly different:

如果您使用 VM 选项运行您的应用程序,然后想在您的应用程序中访问该选项,则必须稍微不同:

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

Your PropertyPlaceholderConfigurer is not aware of system properties, also note that you are accessing properties using $- which refers to place holders and #refers to beans, where systemPropertiesis a bean.

您的 PropertyPlaceholderConfigurer 不知道系统属性,还请注意,您正在使用$-访问属性- 指的是占位符,#指的是豆类,其中systemProperties是豆类。

回答by George Hilios

For any other poor souls who couldn't get this to work in some Configuration classes when they work in others:

对于在其他配置类中工作时无法使其在某些配置类中工作的任何其他可怜人:

Look to see what other beans you have in that class and if any of them get instantiated early in the ApplicationContext. A ConversionService is an example of one. This would instantiate the Configuration class before what is required is registered, thereby making no property injection take place.

查看该类中还有哪些其他 bean,以及它们中的任何一个是否在 ApplicationContext 中尽早实例化。ConversionService 就是一个例子。这将在注册所需内容之前实例化 Configuration 类,从而不会发生属性注入。

I fixed this by moving the ConversionService to another Configuration class that I Imported.

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