以编程方式访问由属性占位符创建的属性
Posted
技术标签:
【中文标题】以编程方式访问由属性占位符创建的属性【英文标题】:Programmatic access to properties created by property-placeholder 【发布时间】:2012-07-10 01:42:14 【问题描述】:我正在使用context:property-placeholder
读取属性文件。我如何以编程方式访问它们(@Value
不起作用 - 我在开发时不知道财产所有权)?
主要问题是我无法更改applicationContext.xml
文件,因为它是由“父”框架设置的
ps。这很奇怪,但Environment.getProperty
返回null
【问题讨论】:
见***.com/questions/5172392/…。从春季 3 开始,这似乎是可能的。 【参考方案1】:不,你不能。 PropertyPlaceholderConfigurer
是 BeanFactoryPostProcessor
,它仅在 bean 创建期间“活着”。当它遇到$property
表示法时,它会尝试根据其内部属性来解决它,但它不会使这些属性对容器可用。
也就是说:类似的问题一次又一次地出现,建议的解决方案通常是to subclass PropertyPlaceHolderConfigurer
并手动将属性提供给上下文。或use a PropertiesFactoryBean
【讨论】:
其实你可以通过编程方式从Spring env中访问属性没有问题 for (MutablePropertySource propertySource : env.getPropertySources()) // PropertySource propertySource = (PropertySource) element; if (propertySource instanceof MapPropertySource) mps = (MapPropertySource) propertySource; @tom true,但是这个功能是在这个答案几年后引入的:-)【参考方案2】:我们使用以下方法来访问我们的应用程序的属性
<util:properties id="appProperties" location="classpath:app-config.properties" />
<context:property-placeholder properties-ref="appProperties"/>
然后,您可以使用限定符将属性自动装配到 bean 中。
@Component
public class PropertyAccessBean
private Properties properties;
@Autowired
@Qualifier("appProperties")
public void setProperties(Properties properties)
this.properties = properties;
public void doSomething()
String property = properties.getProperty("code.version");
如果您有更复杂的属性,您仍然可以使用 ignore-resource-not-found 和 ignore-unresolvable。我们使用这种方法来外部化我们的一些应用程序设置。
<util:properties id="appProperties" ignore-resource-not-found="true"
location="classpath:build.properties,classpath:application.properties,
file:/data/override.properties"/>
<context:property-placeholder ignore-unresolvable="true" properties-ref="appProperties"/>
【讨论】:
【参考方案3】:@Value
注释适用于 Spring 的新版本(在 v3.2.2 上测试) 以下是它的完成方式:
在 spring 配置文件中映射你的属性文件
<!--Import Info:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd-->
<context:property-placeholder location="classpath:/app-config.properties" />
在(根)您的源文件夹中创建 app-config.properties
my.property=test
my.property2=test2
创建一个控制器类
@Controller
public class XRDSBuilder
@Value("$my.property")
private String myProperty;
public String getMyProperty() return myProperty;
Spring 会自动将 my.property 的内容映射到控制器内的变量
Mapping to a list
属性值:
my.list.property=test,test2,test3
控制器类配置:
@Value("#'$my.list.property'.split(',')")
private List<String> myListProperty;
Advanced mapping
@Component("PropertySplitter")
public class PropertySplitter
/**
* Example: one.example.property = KEY1:VALUE1,KEY2:VALUE2
*/
public Map<String, String> map(String property)
return this.map(property, ",");
/**
* Example: one.example.property = KEY1:VALUE1.1,VALUE1.2;KEY2:VALUE2.1,VALUE2.2
*/
public Map<String, List<String>> mapOfList(String property)
Map<String, String> map = this.map(property, ";");
Map<String, List<String>> mapOfList = new HashMap<>();
for (Entry<String, String> entry : map.entrySet())
mapOfList.put(entry.getKey(), this.list(entry.getValue()));
return mapOfList;
/**
* Example: one.example.property = VALUE1,VALUE2,VALUE3,VALUE4
*/
public List<String> list(String property)
return this.list(property, ",");
/**
* Example: one.example.property = VALUE1.1,VALUE1.2;VALUE2.1,VALUE2.2
*/
public List<List<String>> groupedList(String property)
List<String> unGroupedList = this.list(property, ";");
List<List<String>> groupedList = new ArrayList<>();
for (String group : unGroupedList)
groupedList.add(this.list(group));
return groupedList;
private List<String> list(String property, String splitter)
return Splitter.on(splitter).omitEmptyStrings().trimResults().splitToList(property);
private Map<String, String> map(String property, String splitter)
return Splitter.on(splitter).omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(property);
属性值:
my.complex.property=test1:value1,test2:value2
控制器类:
@Value("#PropertySplitter.map('$my.complex.property')")
Map<String, String> myComplexProperty;
【讨论】:
这并没有回答上述问题。 当前的 Mule ESB 3.7.3 运行时是否有效?我无法找到解决方案,它给了我一个错误,例如Failed to convert property value of type 'java.util.ArrayList' to required type 'java.util.List' for property 'messageProcessors'
【参考方案4】:
Spring 遵循 Inversion Of Control 方法,这意味着我们可以简单地将特定属性注入 POJO。但是在某些情况下,当您想直接从代码中访问按名称给出的属性时——有些人可能会认为它是反模式——这显然是正确的,但让我们专注于如何做到这一点。
下面的PropertiesAccessor
提供对Property Placeholder
加载的属性的访问并封装容器特定的东西。它还会缓存找到的属性,因为调用 AbstractBeanFactory#resolveEmbeddedValue(String)
并不便宜。
@Named
public class PropertiesAccessor
private final AbstractBeanFactory beanFactory;
private final Map<String,String> cache = new ConcurrentHashMap<>();
@Inject
protected PropertiesAccessor(AbstractBeanFactory beanFactory)
this.beanFactory = beanFactory;
public String getProperty(String key)
if(cache.containsKey(key))
return cache.get(key);
String foundProp = null;
try
foundProp = beanFactory.resolveEmbeddedValue("$" + key.trim() + "");
cache.put(key,foundProp);
catch (IllegalArgumentException ex)
// ok - property was not found
return foundProp;
【讨论】:
【参考方案5】:在以下网站找到答案:
http://forum.spring.io/forum/spring-projects/container/106180-programmatic-access-to-properties-defined-for-the-propertyplaceholderconfigurer
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="propertyConfigurer">
<property name="properties" ref="props" />
</bean>
<bean id="props" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="file:C:/CONFIG/settings.properties"/>
</bean>
【讨论】:
【参考方案6】:<util:properties id="prop" location="location of prop file" />
这会返回 java.util.Properties 对象
在 JAVA 代码中
Properties prop = (Properties) context.getBean("prop");
现在你可以访问了,
prop.getProperty("key");
【讨论】:
【参考方案7】:在将属性放入属性占位符之前为您的属性创建 bean,以使属性易于在代码中访问。
例如:
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="resources" value="classpath:META-INF/spring/config.properties" />
</bean>
<context:property-placeholder properties-ref="configProperties" ignore-unresolvable="true"/>
代码:
@Autowired
private PropertiesFactoryBean configProperties;
你也可以使用@Resource(name="configProperties")
【讨论】:
【参考方案8】:如果您需要扫描多个位置的属性,这很有效...
<bean id="yourProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<array value-type="org.springframework.core.io.Resource">
<value>classpath:yourProperties.properties</value>
<value>file:../conf/yourProperties.properties</value>
<value>file:conf/yourProperties.properties</value>
<value>file:yourProperties.properties</value>
</array>
</property>
<property name="ignoreResourceNotFound" value="true" />
</bean>
<context:property-placeholder properties-ref="yourProperties" ignore-unresolvable="true"/>
然后在你的实际课程中......
@Autowired
Properties yourProperties;
使用 Spring 5.1.4 测试
【讨论】:
【参考方案9】:假设您在那个“父”框架中定义了属性文件
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:main.properties" />
</bean>
你可以这样使用@Value注解:
@Value( value = "#applicationProperties['my.app.property']" )
private String myProperty;
【讨论】:
在 Spring 4 中遇到错误:不支持对类型 'org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' 的索引 就像@SeanPatrickFloyd 评论的那样:“类似的问题一次又一次地出现,建议的解决方案通常是继承 PropertyPlaceHolderConfigurer 并手动使 Properties 可用于上下文。或者使用 PropertiesFactoryBean 。”希望对您有所帮助:Reading-valued-from-properties-file-at-Runtime以上是关于以编程方式访问由属性占位符创建的属性的主要内容,如果未能解决你的问题,请参考以下文章
spring 的 PropertyPlaceholderConfigurer读取的属性怎么访问 (java访问方式,不是xml中的占位符哦)