Spring 带有 PropertyPlaceholderConfigurer bean 的 @Configuration 文件不解析 @Value 注释
Spring @Configuration file with PropertyPlaceholderConfigurer bean doesn't resolve @Value annotation
我有以下配置文件:
@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 创建移动到该配置文件 - 字段值再次为 null。
作为解决方法,我使用了这行代码:
System.getProperties().getProperty("property", "defaultValue")
这也是可行的,但我想知道为什么会出现这种行为,也许可以用其他方式重写它但没有 xml?
如果您 运行 您的应用程序使用 VM 选项,然后想在您的应用程序中访问该选项,您必须稍微不同地进行操作:
@Value("#{systemProperties.property}")
private String property;
您的 PropertyPlaceholderConfigurer 不知道系统属性,还要注意您正在使用 $
访问属性 - 它指的是占位符,#
指的是 beans,其中 systemProperties
是一颗豆子。
来自 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 context:property-placeholder 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.
因此,您正在尝试在启用占位符处理所需的代码块中使用占位符。
如@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();
}
}
更新 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;
}
对于任何其他无法在某些配置中工作的可怜人 classes,当他们在其他配置中工作时:
查看您在那个 class 中还有哪些其他 bean,以及它们中的任何一个是否在 ApplicationContext 的早期实例化。 ConversionService 就是一个例子。这将在注册所需内容之前实例化配置 class,从而不会发生 属性 注入。
我通过将 ConversionService 移动到我导入的另一个配置 class 来解决这个问题。
我有以下配置文件:
@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 创建移动到该配置文件 - 字段值再次为 null。
作为解决方法,我使用了这行代码:
System.getProperties().getProperty("property", "defaultValue")
这也是可行的,但我想知道为什么会出现这种行为,也许可以用其他方式重写它但没有 xml?
如果您 运行 您的应用程序使用 VM 选项,然后想在您的应用程序中访问该选项,您必须稍微不同地进行操作:
@Value("#{systemProperties.property}")
private String property;
您的 PropertyPlaceholderConfigurer 不知道系统属性,还要注意您正在使用 $
访问属性 - 它指的是占位符,#
指的是 beans,其中 systemProperties
是一颗豆子。
来自 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 context:property-placeholder 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.
因此,您正在尝试在启用占位符处理所需的代码块中使用占位符。
如@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();
}
}
更新 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;
}
对于任何其他无法在某些配置中工作的可怜人 classes,当他们在其他配置中工作时:
查看您在那个 class 中还有哪些其他 bean,以及它们中的任何一个是否在 ApplicationContext 的早期实例化。 ConversionService 就是一个例子。这将在注册所需内容之前实例化配置 class,从而不会发生 属性 注入。
我通过将 ConversionService 移动到我导入的另一个配置 class 来解决这个问题。