SPRING多个占位符配置文件解析源码研究--转
原文地址:http://www.cnphp6.com/archives/85639
Spring配置文件:
<context:property-placeholder location="classpath:/settings.properties" />
<context:property-placeholder location="classpath:/conf.properties"/>
settings.properties
redis.masterName=mymaster
conf.properties
home.abroad=1
测试类:
@Component
public class PropertyPlaceHolderTest {
@Value("${redis.masterName}")
String masterName;
@Value("${home.abroad}")
int homeAbroad;
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext-test.xml");
PropertyPlaceHolderTest bean = ctx.getBean(PropertyPlaceHolderTest.class);
System.out.println(ToStringBuilder.reflectionToString(bean));
}
}
执行上述测试类 报错:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'home.abroad' in string value [${home.abroad}]
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:173)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:125)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:151)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:142)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:169)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:748)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:745)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
... 15 more
为什么只能解析出第一个property-placeholder配置中的key?第二个property-placeholder配置文件中的key是被忽略了吗?
但明明日志显示两个配置文件均被成功解析了啊。
INFO org.springframework.context.support.PropertySourcesPlaceholderConfigurer Loading properties file from class path resource [settings.properties]
INFO org.springframework.context.support.PropertySourcesPlaceholderConfigurer Loading properties file from class path resource [conf.properties]
那到底是什么原因呢?只有分析源代码了。发现一旦解析配置文件后会将其封装到一个PropertySourcesPropertyResolver对象中,如下所示:
//所属类:PropertySourcesPlaceholderConfigurer
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//......
this.processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
}
再创建一个StringValueResolver对象,实际使用上面的PropertySourcesPropertyResolver对象来解析占位符中的字符串。
//所属类:PropertySourcesPlaceholderConfigurer
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
final ConfigurablePropertyResolver propertyResolver) throws BeansException {
//......
StringValueResolver valueResolver = new StringValueResolver() {
public String resolveStringValue(String strVal) {
String resolved = ignoreUnresolvablePlaceholders ?
propertyResolver.resolvePlaceholders(strVal) :
propertyResolver.resolveRequiredPlaceholders(strVal);
return (resolved.equals(nullValue) ? null : resolved);
}
};
doProcessProperties(beanFactoryToProcess, valueResolver);
}
最后将此StringValueResolver对象放入到一个List中,
//所属类:AbstractBeanFactory
public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
Assert.notNull(valueResolver, "StringValueResolver must not be null");
this.embeddedValueResolvers.add(valueResolver);
}
当自动注入@Value标注的字段时,
DEBUG org.springframework.beans.factory.annotation.InjectionMetadata Processing injected method of bean 'propertyPlaceHolderTest': AutowiredFieldElement for int com.tcl.test.PropertyPlaceHolderTest.homeAbroad
需要解析@Value中的占位符中的内容了,涉及到源码是:
//所属类:AbstractBeanFactory
public String resolveEmbeddedValue(String value) {
String result = value;
for (StringValueResolver resolver : this.embeddedValueResolvers) {
result = resolver.resolveStringValue(result);
}
return result;
}
从之前描述可知this.embeddedValueResolvers中有两个valueResolver对象(分别对应两个context:property-placeholder元素),于是先取出第一个valueResolver(对应settings.properties)来解析${home.abroad},而它是配置在conf.poperties中的,肯定解析不到,于是就报错了,见源代码:
//所属的类与方法:PropertyPlaceholderHelper.parseStringValue
if (propVal != null) {
//......
}
else if (this.ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = buf.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
throw new IllegalArgumentException("Could not resolve placeholder '" +
placeholder + "'" + " in string value [" + strVal + "]");
}
但明明才遍历了List中第一个valueResolver对象呢,后面的那个可以成功解析啊。错误抛的也太急了点吧。
Spring肯定也考虑了这一点,从上面的源代码也可以看出,只要设置了ignoreUnresolvablePlaceholders为true的话,就不会走最后的else分支了。
修改Spring配置,显式指定第一个context:property-placeholder元素ignore-unresolvable属性为true,如下所示:
<context:property-placeholder location="classpath:/settings.properties" ignore-unresolvable="true"/>
<context:property-placeholder location="classpath:/conf.properties"/>
这时就不会报错了,${home.abroad}也能被成功解析了。见输出:
com.tcl.test.PropertyPlaceHolderTest@2f949a6b[masterName=mymaster,homeAbroad=1]
当然正常情况下没必要配置成两个或多个context:property-placeholder,完全可以用一个context:property-placeholder来指定多个配置文件,如下所示:
<context:property-placeholder location="classpath:/settings.properties,/conf.properties" />
最新文章
- EntityFramework Core 1.1是如何创建DbContext实例的呢?
- 使用Angular2理由
- 【POI】使用POI处理xlsx的cell中的超链接 和 插入图片 和 设置打印区域
- Servlet 获取 ApplicationContext
- Axure轮播图
- linux 全自动提权 exp perl脚本
- Xcode 快捷键操作
- BUILD_BUG_ON 的解释
- 计算机体系结构-内存调优IPC OOMK
- glibc的了解,对内核的封装
- (Java 多线程系列)java volatile详解
- IOS CrackMe 破解学习
- bzoj 4653: [Noi2016]区间
- leetcode-查找和替换模式
- js绑定下拉框
- TCP/IP协议详解内容总结(怒喷一口老血)
- Golang中使用kafka
- Linux split命令详解
- Use JAWS 14 in a VM
- Android——手机尺寸相关的概念 +尺寸单位+关于颜色
热门文章
- 步骤进度条 css
- jQuery中事件与动画的总结
- 安卓初級教程(4):sqlite建立資料庫
- CYQ.Data 支持WPF相关的数据控件绑定(2013-08-09)
- 深圳电信光纤用户必备:简单破解中兴ZXA10 F460光电猫,实现WIFI和自动拨号功能
- 浅谈WEB跨域的实现(前端向)
- java中文乱码解决之道(六)-----javaWeb中的编码解码
- 【java并发编程实战】-----线程基本概念
- Javascript中相同Function使用多个名称
- [nRF51822] 10、基础实验代码解析大全 &#183; 实验15 - RTC