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" />
SPRING多个占位符配置文件解析源码研究--转的更多相关文章
- spring源码分析之配置文件名占位符的解析(一)
一.直接写个测试例子 package com.test; import org.junit.Test; import org.springframework.context.ApplicationCo ...
- Spring Cloud Finchley.SR1 版本的坑:placeholer占位符无法解析!
接入nacos 之后,想把所有的配置丢上去. 启动程序是: @EnableDiscoveryClient @RestController @ComponentScan(basePackages = { ...
- Spring 利用PropertyPlaceholderConfigurer占位符
Hey Girl 博客园 首页 博问 闪存 新随笔 订阅 管理 posts - 42, comments - 3, trackbacks - 0 Sp ...
- dubbo注册中心占位符无法解析问题
dubbo注册中心占位符无法解析问题 1.背景 最近搞了2个老项目,想把他们融合到一起.这俩项目情况简介如下: 项目一:基于SpringMVC + dubbo,配置读取本地properties文件,少 ...
- Spring中AOP相关的API及源码解析
Spring中AOP相关的API及源码解析 本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring ...
- dubbo注册中心占位符无法解析问题(二)
dubbo注册中心占位符无法解析问题 前面分析了dubbo注册中心占位符无法解析的问题. 并给出了2种解决办法: 降低mybatis-spring的版本至2.0.1及以下 自定义MapperScann ...
- spring事务详解(三)源码详解
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- Flink 源码解析 —— 源码编译运行
更新一篇知识星球里面的源码分析文章,去年写的,周末自己录了个视频,大家看下效果好吗?如果好的话,后面补录发在知识星球里面的其他源码解析文章. 前言 之前自己本地 clone 了 Flink 的源码,编 ...
- Spring Boot核心技术之Rest映射以及源码的分析
Spring Boot核心技术之Rest映射以及源码的分析 该博客主要是Rest映射以及源码的分析,主要是思路的学习.SpringBoot版本:2.4.9 环境的搭建 主要分两部分: Index.ht ...
随机推荐
- html5地理位置定位功能小析
Geolocationd 基本原理1.GPS GPS基本原理是测量出已知位置的卫星到用户接收机之间的距离,然后综合多颗卫星的数据就可知道接收机的具体位置.适用于具备GPS功能的设备(1)优点:在 ...
- flex的兼容
父容器的 display 属性: .box{ display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older WebKit br ...
- angularjs 解决ng-repeat数组内重复对象报错的问题
ng-repeat 循环数组内元素时,如果数组内元素重复,angular会抛出异常: Error: [ngRepeat:dupes] http://errors.angularjs.org/1.4.3 ...
- Public key for mysql....rpm is not installed
解决方案: 此时导入rpm的签名信息即可,用root登录,执行下面命令(我的linux版本是centos 5.1) 原文地址: http://my.oschina.net/u/555639/blog/ ...
- 通过反射获取DLL的类实现加载窗体
1.创建一个DLL 类库,并新建一个窗体类,这个直接在vs上操作就好 2. 建立一个Testassembly工程 新建一个测试类 namespace Testassembly { public par ...
- window.location.href 中文乱码问题。。。。
window.location.href 中文乱码问题.... 要解决此问题需要两次解码, 第一次解码: 是在页面中的js脚本中解码:window.location.href = "save ...
- SQL语句到底是怎么执行的
写在前面的话:有时不理解SQL语句各个部分执行顺序,导致理解上出现偏差,或者是书写SQL语句时随心所欲,所以有必要了解一下sql语句的执行顺序.可以有时间自己写一个简单的数据库,理解会更加深入.下面就 ...
- JavaScript面试时候的坑洼沟洄——数据类型
前些日子写了篇关于最近找工作的一些感受的博客 找工作的一些感悟--前端小菜的成长,没想到得到了很多园友的共鸣,得到了很多鼓励,也有园友希望我分享一些笔试.面试的经验.我觉得分享一些笔试题没太多价值,对 ...
- 老司机学新平台 - Xamarin开发之我的第一个MvvmCross跨平台插件:SimpleAudioPlayer
大家好,老司机学Xamarin系列又来啦!上一篇MvvmCross插件精选文末提到,Xamarin平台下,一直没找到一个可用的跨平台AudioPlayer插件.那就自力更生,让我们就自己来写一个吧! ...
- Fig 应用编排
Fig是Docker的应用编排工具,主要用来跟 Docker 一起来构建基于 Docker 的复杂应用,Fig 通过一个配置文件来管理多个Docker容器,非常适合组合使用多个容器进行开发的场景. 说 ...