相信很多朋友都使用过如下代码进行可变数据的占位符替换。
<context:property-placeholder location="classpath:resources.properties" ignore-unresolvable="true"/>
最近使用maven profile + maven资源过滤 + spring3.2进行开发,如果不小心忘了maven的资源过滤,或者如遇到这种abc=${bcd} 这种循环引用时,且bcd不存在时,即:
如果代码中引用如abc:
@Value("${abc}") private String abc;
且您的配置文件出现如下情况:
abc=${dce} ----->嵌套引用dce属性
dce=${none} --->此时none不存在
如果在spring3.1中,并配置了ignore-unresolvable,那么直接返回${none},而不会在spring3.2中会遇到如下异常(spring3.1不会遇到问题):
java.lang.StackOverflowError at java.security.AccessController.doPrivileged(Native Method) at com.sun.naming.internal.VersionHelper12.getJndiProperties(VersionHelper12.java:106) at com.sun.naming.internal.ResourceManager.getInitialEnvironment(ResourceManager.java:202) at javax.naming.InitialContext.init(InitialContext.java:238) at javax.naming.InitialContext.<init>(InitialContext.java:216) at org.springframework.jndi.JndiTemplate.createInitialContext(JndiTemplate.java:136) at org.springframework.jndi.JndiTemplate.getContext(JndiTemplate.java:103) at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:85) at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:152) at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:178) at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:95) at org.springframework.jndi.JndiLocatorDelegate.lookup(JndiLocatorDelegate.java:38) at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:77) at org.springframework.jndi.JndiLocatorDelegate.lookup(JndiLocatorDelegate.java:33) at org.springframework.jndi.JndiPropertySource.getProperty(JndiPropertySource.java:82) at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:73) at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:59) at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:427) at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$1.getProperty(PropertySourcesPlaceholderConfigurer.java:131) at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$1.getProperty(PropertySourcesPlaceholderConfigurer.java:128) at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:73) at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:59) at org.springframework.core.env.AbstractPropertyResolver$1.resolvePlaceholder(AbstractPropertyResolver.java:176) at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:146) at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:125)
其实就是死循环了,造成栈溢出。
源码分析:
1、<context:property-placeholder> 实际使用的是org.springframework.context.support.PropertySourcesPlaceholderConfigurer,其是一个BeanFactory后处理器(BeanFactoryPostProcessor):
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, final ConfigurablePropertyResolver propertyResolver) throws BeansException { propertyResolver.setPlaceholderPrefix(this.placeholderPrefix); propertyResolver.setPlaceholderSuffix(this.placeholderSuffix); propertyResolver.setValueSeparator(this.valueSeparator); 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); }
1.1、此处根据ignoreUnresolvablePlaceholders(<context:property-placeholder>中的ignore-unresolvable)决定是否必须查找到占位符的值,
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { ……………… this.processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources)); }
1.2、最后一行直接委托给了processProperties方法 并传入了PropertySourcesPropertyResolver,这个是核心,问题就出在这;
1.3、然后不管propertyResolver.propertyResolver.resolvePlaceholders还是propertyResolver.resolveRequiredPlaceholders都会调用:
return doResolvePlaceholders(text, strictHelper/nonStrictHelper);
只是此处一个使用严格的PropertyPlaceholderHelper 另一个是不严格的PropertyPlaceholderHelper;
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) { return helper.replacePlaceholders(text, new PlaceholderResolver() { public String resolvePlaceholder(String placeholderName) { return getProperty(placeholderName); } }); }
1.4、 此时调用helper的
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) { Assert.notNull(value, "Argument 'value' must not be null."); return parseStringValue(value, placeholderResolver, new HashSet<String>()); }
1.5、parseStringValue方法:
如果发现如abc=${dce},那么会接着调用如下代码接着循环找值
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
1.6、最终会调用1.3中的getProperty方法去获取值,即此时key是dce:
public String getProperty(String key) { if (logger.isTraceEnabled()) { logger.trace(format("getProperty(\"%s\") (implicit targetType [String])", key)); } return this.getProperty(key, String.class); }
最终会调用:
if (String.class.equals(valueType)) { value = this.resolveNestedPlaceholders((String) value); }
1.7、到了resolveNestedPlaceholders
protected String resolveNestedPlaceholders(String value) { return this.ignoreUnresolvableNestedPlaceholders ? this.resolvePlaceholders(value) : this.resolveRequiredPlaceholders(value); }
问题出现了:如果此处的ignoreUnresolvableNestedPlaceholders为false,那么接着又去了resolveRequiredPlaceholders,此是就会死循环问题,spring3.2没有考虑这个问题,所以会造成java.lang.StackOverflowError。
解决方案:
1、spring考虑此循环引用的问题
2、在org.springframework.context.support.PropertySourcesPlaceholderConfigurer中在new PropertySourcesPropertyResolver(this.propertySources)后调用其setIgnoreUnresolvableNestedPlaceholders(ignoreUnresolvablePlaceholders),把ignoreUnresolvablePlaceholders传入即可。
到此分析结束。
相关推荐
context:property-placeholder 和util:properties 博客:https://blog.csdn.net/u010476739/article/details/76735527
主要介绍了Spring整合Mybatis使用<context>时的坑 的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
前端项目-placeholder.js,图像占位符使用画布完全在浏览器中呈现图像占位符。
SSH笔记-通过property-placeholder使用外部属性文件的demo
前端项目-placeholder-shiv,占位符属性的小polyfill。需要prototype.js或jquery
<context:property-placeholder location="classpath:jdbc.properties" /> class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref=...
扩展TextView添加placeholder和maxInputLenth属性,将扩展文件导入即可使用对代码无污染 ...github:https://github.com/cccgoodboy/UITextView-placeholder-maxInputLenth 觉得好用请给个star 谢谢!
使用该插件(jquery.placeholder.js)解决IE9及以版本下对placeholder的兼容性问题
15. <context:property-placeholder location="classpath:/hibernate.properties" /> 16. 17. 18. class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 19. <property name=...
防暴占位符 Riot.js插件,用于生成占位符文本。 关于 riot-placeholder是一个简单的riot标签,用于基于riot.js的网站和应用程序的...import placeholder from 'riot-placeholder' placeholder ( riot ) console . l
角占位符垫片 使 input/textarea 占位符属性适用于所有浏览器的 Angular 指令。... script src =" components/angular-placeholder-shim/angular-placeholder-shim.js " > </ script > 将模块placeh
black-hole.js 用来向你展示太空中的黑洞的 JavaScript 库。使用方法:<div id="canvas_placeholder">[removed]... BlackHole.blackHoleifyImage('canvas_placeholder', corsOkImageUrl)[removed] 标签:black
placeholder-geojson-源码.rar
jquery.placeholder.min.js
本篇文章主要介绍了Spring中property-placeholder的使用与解析详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
资源来自pypi官网。 资源全名:wagtail_placeholder_images-0.1.0-py3-none-any.whl
python库,解压后可用。 资源全名:wagtail_placeholder_images-0.1.0-py3-none-any.whl
webpack-image-placeholder-loader 该加载器从给定图像生成彩色或纯色图像,用作占位符。 该程序包在内部使用。 有关从图像派生的,请参见。 支持JPEG,PNG,WebP,TIFF,GIF和SVG图像。 例子 安装 使用npm安装:...
动态占位符图像 用于管理和提供网站使用的动态占位符图像的 这里有什么? ... readme.txt - WordPress 存储库的信息 ...admin/partials - 插件设置的标题 ...class-gga-dynamic-placeholder-images-attachmen