带有 PropertyPlaceholderConfigurer Bean 的 Spring @Configuration文件无法解析@Value注释更新 09/2021

2022-09-02 00:33:55

我有以下配置文件:

@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

因此,我希望我的应用程序在启动时加载特定的属性文件。但是由于某种原因,在此阶段不处理注释,并且属性为 。另一方面,如果我通过xml文件进行配置 - 一切都按预期完美地工作。xml 文件示例:@ValuenullPropertyPlaceholderConfigurer

<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>

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

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

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

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


答案 1

来自Spring JavaDoc

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

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

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

下面的示例演示如何在属性源批注中使用属性,以及如何在字段中从属性源注入属性。

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

更新 09/2021

正如Koray在评论中提到的,自Spring 4.3 + / Spring Boot 1.5 +以来不再需要了。动态文件名可用于 中的属性文件和批注,而无需其他配置。PropertySourcesPlaceholderConfigurer@PropertySource@ConfigurationProperties

@Configuration
@PropertySource(
          value={"classpath:properties/${property:defaultValue}.properties"},
          ignoreResourceNotFound = true)
public class ConfigExample {

    @Value("${propertyNameFromFile:defaultValue}")
    String propertyToBeInjected;
}
@ConfigurationProperties("properties/${property:defaultValue}.properties")
public class ConfigExample {

    String propertyNameFromFile;
}

答案 2

对于任何其他可怜的灵魂,当他们在其他配置类中工作时,他们无法在某些配置类中工作:

查看该类中还有哪些其他 Bean,以及它们中是否有任何一个在 ApplicationContext 的早期实例化。转换服务就是其中之一。这将在注册所需内容之前实例化 Configuration 类,从而使不会进行任何属性注入。

我通过将转换服务移动到我导入的另一个配置类来解决此问题。


推荐