同一容器中创建多个PropertyPlaceholderConfigurer分别注入不同properties发生解析占位符错误的问题

上一篇我们说到父子容器无法共享properties属性值的问题,这次问题发生在同一容器中,废话不多说,上代码

	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:test01.properties</value>
			</list>
		</property>
	</bean>

	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:test02.properties</value>
			</list>
		</property>
	</bean>

	<!-- test01.properties 和 test02.properties 的属性值互不相同 -->

	<bean class="cn.fg.bean.Person">
		<property name="name" value="${name1}" />
	</bean>

启程程序后,控制台报错Could not resolve placeholder 'name1' in value "${name1}"

org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'cn.fg.bean.Person#0' defined in class path resource [spring-mvc.xml]: Could not resolve placeholder 'name1' in value "${name1}"; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'name1' in value "${name1}"
	at org.springframework.beans.factory.config.PlaceholderConfigurerSupport.doProcessProperties(PlaceholderConfigurerSupport.java:223)
	at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.processProperties(PropertySourcesPlaceholderConfigurer.java:180)
	at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:152)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:283)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:163)
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:524)
	at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:668)

为什么?我们点进PlaceholderConfigurerSupport.java:223行、PropertySourcesPlaceholderConfigurer.java:180行

/** 
 * 先看PropertySourcesPlaceholderConfigurer.java:180行,这个函数是在替换占位符
 *
 * Visit each bean definition in the given bean factory and attempt to replace ${...} property
 * placeholders with values from the given properties.
 */
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() {
		@Override
		public String resolveStringValue(String strVal) {
			String resolved = (ignoreUnresolvablePlaceholders ?
					propertyResolver.resolvePlaceholders(strVal) :
					propertyResolver.resolveRequiredPlaceholders(strVal));
			if (trimValues) {
				resolved = resolved.trim();
			}
			return (resolved.equals(nullValue) ? null : resolved);
		}
	};

	//这里点进去就是PlaceholderConfigurerSupport.java:223行
	doProcessProperties(beanFactoryToProcess, valueResolver);
}
//PlaceholderConfigurerSupport.java:223行
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) {

	BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);

	String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
	
	//这里正在遍历所有定义的bean,最终会进入catch报错
	for (String curName : beanNames) {
		// Check that we're not parsing our own bean definition,
		// to avoid failing on unresolvable placeholders in properties file locations.
		if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
			BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
			try {
				visitor.visitBeanDefinition(bd);
			}
			catch (Exception ex) {
				throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
			}
		}
	}

	// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
	beanFactoryToProcess.resolveAliases(valueResolver);

	// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
	beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}

为什么会报错?PropertyPlaceholderConfigurer在初始化时会调用上面两个方法,遍历其他所有的bean定义信息,看有没有使用占位符,然后与自身中的properties对比,是否存在该占位符的属性,若不存在就会报错;由于我们这里定义了两个PropertyPlaceholderConfigurer,而properties的属性也不一样;当其中一个遍历所有bean时,肯定会找不属性,所以就报错了。如何解决?

方式一:两个properties写到一个PropertyPlaceholderConfigurer中

	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:test01.properties</value>
				<value>classpath:test02.properties</value>
			</list>
		</property>
	</bean>

方式二:设置忽略未能解析的占位符为true

	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:test01.properties</value>
			</list>
		</property>
		//增加该属性值为true
		<property name="ignoreUnresolvablePlaceholders" value="true"></property>
	</bean>

	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:test02.properties</value>
			</list>
		</property>
		<property name="ignoreUnresolvablePlaceholders" value="true"></property>
	</bean>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值