`
jinnianshilongnian
  • 浏览: 21529779 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2423372
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:3012924
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5642390
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:260687
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1598924
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:250657
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5863391
Group-logo
跟我学Nginx+Lua开...
浏览量:703643
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:786822
社区版块
存档分类
最新评论

Spring3.2 bug 嵌套context:property-placeholder替换的java.lang.StackOverflowError异常分析

 
阅读更多

相信很多朋友都使用过如下代码进行可变数据的占位符替换。

 

<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传入即可。

 

到此分析结束。

 

 

5
2
分享到:
评论
1 楼 85977328 2013-05-14  
经常看到开涛的文章,顶~

相关推荐

    context:property-placeholder 和util:properties

    context:property-placeholder 和util:properties 博客:https://blog.csdn.net/u010476739/article/details/76735527

    Spring整合Mybatis使用&lt;context:property-placeholder&gt;时的坑

    5. 使用Spring的`PropertySourcesPlaceholderConfigurer`代替`&lt;context:property-placeholder&gt;`,它提供了更多的灵活性和控制,比如可以配置多个`PropertySource`,分别对应不同的属性文件。 6. 确认Spring配置文件...

    SSH笔记-通过property-placeholder使用外部属性文件

    在Spring框架中,`&lt;context:property-placeholder&gt;`是用于加载和解析属性文件的一个标签,它允许我们在XML配置或Java配置中使用占位符 `${...}` 来引用属性文件中的值。这样做的好处是,我们可以将敏感信息如数据库...

    spring_MVC源码

    15. &lt;context:property-placeholder location="classpath:/hibernate.properties" /&gt; 16. 17. 18. class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"&gt; 19. &lt;property name=...

    spring-framework-3.2.0.RC2-schema.zip

    `context`命名空间下的 `&lt;context:component-scan&gt;`、`&lt;context:property-placeholder&gt;`等元素,用于扫描组件、加载外部属性文件,增强了Spring的应用范围和灵活性。 "cache"模块则提供了缓存抽象,支持如 EhCache...

    Spring中property-placeholder的使用与解析详解

    Spring 中 property-placeholder 的使用与解析详解 -property-placeholder 是 Spring 框架中的一种机制,用于加载和解析 properties 文件中的配置信息。在本文中,我们将详细介绍 property-placeholder 的使用和...

    前端项目-placeholder.js.zip

    前端项目-placeholder.js,图像占位符使用画布完全在浏览器中呈现图像占位符。

    前端项目-placeholder-shiv.zip

    标题中的"前端项目-placeholder-shiv.zip"表明这是一个与前端开发相关的项目,具体是关于"placeholder-shiv"。在前端开发中,"placeholder"通常指的是HTML5中的一个特性,即输入框(input)的提示文本,当用户聚焦...

    spring3.0的xsd文件.rar

    此外,`&lt;context:property-placeholder&gt;`则可以用来加载属性文件,方便在配置中引用环境变量。 Spring 3.0引入了AOP(Aspect-Oriented Programming,面向切面编程)的增强,`aop.xsd`定义了与切面相关的配置元素,...

    17 Spring IoC容器如何读取多个属性文件或者配置文件?慕课专栏(1)1

    在Spring的老版本中,通常使用`&lt;context:property-placeholder&gt;`或`&lt;util:properties&gt;`元素来加载属性文件。例如: ```xml &lt;!-- 使用 context:property-placeholder --&gt; &lt;beans xmlns="http://...

    引入多个properties时.txt

    在`applicationContext.xml`中通过`&lt;context:property-placeholder&gt;`标签来指定`properties`文件的位置。例如,我们需要引入两个文件:`jdbc.properties`和`res.properties`,可以这样配置: ```xml &lt;!-- 引入 jdbc...

    java 获取properties的几种方式(csdn)————程序.pdf

    例如,Spring的`PropertyPlaceholderConfigurer`和`&lt;context:property-placeholder&gt;`适用于Spring应用,而`ResourceBundle`适合处理本地化,`Properties`类则是一个通用解决方案。理解并熟练掌握这些方法,将有助于...

    集成springmvc spring hibernate的配置

    在开发Java Web应用程序时,常常会采用Spring MVC、Spring和Hibernate这三大框架进行集成,以实现高效的业务逻辑处理和持久化操作。以下是关于这些框架集成的详细配置过程: 首先,我们需要创建一个项目结构,通常...

    struts2.3+hibernate3.6+spring3.1整合的纯xml配置的小项目

    &lt;context:property-placeholder location="classpath:jdbc.properties" /&gt; class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"&gt; &lt;property name="dataSource" ref=...

    ssh整合步骤一站式

    &lt;context:property-placeholder location="classpath:jdbc.properties" /&gt; &lt;aop:aspectj-autoproxy /&gt; ``` - 上述配置中,`context:annotation-config`用于启用注解支持;`context:component-scan`用于扫描...

    ios-TextView placeholder maxInputLenth.zip

    扩展TextView添加placeholder和maxInputLenth属性,将扩展文件导入即可使用对代码无污染 ...github:https://github.com/cccgoodboy/UITextView-placeholder-maxInputLenth 觉得好用请给个star 谢谢!

    基于java的企业级应用开发:Mybatis与Spring的整合.ppt

    然后,在`applicationContext.xml`中,配置Spring的基本信息,如数据源(使用`BasicDataSource`),并引用`db.properties`,通过`context:property-placeholder`标签加载属性文件。接下来,配置MyBatis的`mybatis-...

    修改输入框placeholder文字默认颜色-webkit-input-placeholder方法

    在网页设计中,输入框(`&lt;input&gt;`)的占位符(`placeholder`)属性是一种非常实用的功能,它可以在用户输入前提供提示文本。HTML5引入了这一原生属性,使得开发者能够轻松地在输入框中添加提示信息。默认情况下,...

    spring mongodb整合

    在Spring框架中整合MongoDB是一个常见的任务,它允许我们利用Spring Data MongoDB库来简化与MongoDB数据库的交互。以下是如何进行Spring MongoDB整合的详细步骤和相关知识点: 1. **依赖管理**: - `spring-core-...

    前端项目-ng-sortable.zip

    placeholder: 'placeholder' // 可选,设置占位符类名 }, items: [/* your data array */] }; // 添加事件监听 $scope.$on('asortable:start', function(event, element, modelValue) { // 拖放开始时的...

Global site tag (gtag.js) - Google Analytics