带有 PropertyPlaceholderConfigurer bean 的 Spring @Configuration 文件不解析 @Value 注释
Posted
技术标签:
【中文标题】带有 PropertyPlaceholderConfigurer bean 的 Spring @Configuration 文件不解析 @Value 注释【英文标题】:Spring @Configuration file with PropertyPlaceholderConfigurer bean doesn't resolve @Value annotation 【发布时间】:2016-01-25 12:02:52 【问题描述】:我有以下配置文件:
@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 文件配置了PropertyPlaceholderConfigurer
- 一切都按预期完美运行。 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>
如果我尝试在另一个 Spring 配置文件中注入属性值 - 它被正确注入。如果我将 PropertyPlaceholderConfigurer
bean 创建移动到该配置文件 - 字段值再次为空。
作为解决方法,我使用这行代码:
System.getProperties().getProperty("property", "defaultValue")
这也是可行的,但我想知道为什么会发生这种行为,也许可以用其他方式重写它但没有 xml?
【问题讨论】:
首先我强烈建议您使用ProperySourcesPlaceholderConfigurer
,并在您的课堂上使用@PropertySource
。其次,bean 需要是static
。
@M.Deinum @PropertySource
非常适合我,但是如果我有 ProperySourcesPlaceholderConfigurer
的自定义实现呢?
为什么需要自定义实现。
@M.Deinum 例如从 ZooKeeper 加载属性
您不需要自定义实现,您需要自定义PropertySource
【参考方案1】:
来自春天JavaDoc:
为了使用 PropertySource 中的属性解析定义中的 $... 占位符或 @Value 注释,必须注册一个 PropertySourcesPlaceholderConfigurer。这在 XML 中使用 context:property-placeholder 时会自动发生,但在使用 @Configuration 类时必须使用静态 @Bean 方法显式注册。有关详细信息和示例,请参阅 @Configuration 的 javadoc 的“使用外部值”部分和 @Bean 的 javadoc 的“关于 BeanFactoryPostProcessor-returning @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();
2021 年 9 月更新
正如 Koray 在评论中提到的,PropertySourcesPlaceholderConfigurer
自 Spring 4.3+ / Spring Boot 1.5+ 起不再需要。动态文件名可以用于@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;
【讨论】:
如果我想在 bean 创建方法中添加额外的属性怎么办?我正在手动加载我的 yaml 文件属性,并希望将其添加到 PropertySources 我认为 处理 @Value 注释所需的属性占位符配置器不再适用,因为 Spring 4.3 和propertyConfigurer()
可以从示例中删除?【参考方案2】:
对于在其他配置类中工作时无法使其在某些配置类中工作的任何其他可怜的灵魂:
查看您在该类中还有哪些其他 bean,以及它们中的任何一个是否在 ApplicationContext 的早期实例化。 ConversionService 就是其中的一个示例。这将在注册所需内容之前实例化配置类,从而不会发生属性注入。
我通过将 ConversionService 移动到我导入的另一个配置类来解决此问题。
【讨论】:
另一种可能性是使用构造函数注入,如下所述:***.com/questions/28636060/spring-value-often-null【参考方案3】:如果您使用 VM 选项运行您的应用程序,然后想在您的应用程序中访问该选项,您必须做的稍有不同:
@Value("#systemProperties.property")
private String property;
您的 PropertyPlaceholderConfigurer 不知道系统属性,还请注意您正在使用 $
访问属性 - 它指的是占位符,#
指的是 bean,其中 systemProperties
是一个 bean。
【讨论】:
不幸的是,它在我创建 PropertyPlaceholderConfigurer bean 的配置中不起作用,但在任何其他配置文件中都起作用以上是关于带有 PropertyPlaceholderConfigurer bean 的 Spring @Configuration 文件不解析 @Value 注释的主要内容,如果未能解决你的问题,请参考以下文章
带有多个链接的 NSAttributedString 的 UILabel,带有行限制,显示尾部截断,带有未见文本的 NSBackgroundColorAttributeName
使用带有 uuencode 的“sendmail”发送邮件,并带有主题
如何翻转正面带有标签而背面带有另一个标签的视图 - 参见图片