情况说明
模块A中Spring 配置文件中注入'a.properties',如下
<context:property-placeholder location="classpath:a.properties"/>
模块B中Spring 配置文件中注入'b.properties',如下
<context:property-placeholder location="classpath:b.properties"/>
b.properties
中配置如下
person.name=zhangsan
模块C中Spring 配置文件中注入'c.properties',如下
<context:property-placeholder location="classpath:c.properties"/>
模块A和模块B单独运行都没问题,但是模块C集成模块A与模块B启动容器出错:
Could not resolve placeholder 'person.name' in value "${person.name}"
问题原因
Spring容器采用反射扫描的发现机制,在探测到Spring容器中有一个org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
的Bean就会停止对剩余PropertyPlaceholderConfigurer
的扫描。而<context:property-placeholder/>
这个基于命名空间的配置,其实内部就是创建一个PropertyPlaceholderConfigurer
Bean而已。Spring容器允许定义多个PropertyPlaceholderConfigurer
(或<context:property-placeholder/>
),但定义多个PropertyPlaceholderConfigurer
时默认执行顺序是无序的,且在定义第一个PropertyPlaceholderConfigurer
bean的时候,如果没找到对应的属性,默认会抛出异常。
即如果先定义的是模块A中配置器,该配置器只会加载它对应的属性配置文件,但是此时会扫描整个容器中(模块A,模块B...)中的bean,发现有模块B中定义的bean中的占位符无法解析,直接抛出异常。
解决方式
指定配置器执行顺序'order',只让最后一个配置器解析不了占位符的时候抛出异常,其他的配置器在解析不了占位符时,交给后面的配置器去解析。
模块A中Spring 配置文件中注入'a.properties',如下
<context:property-placeholder location="classpath:a.properties" order="1" ignore-unresolvable="true"/>
模块B中Spring 配置文件中注入'b.properties',如下
<context:property-placeholder location="classpath:b.properties" order="2" ignore-unresolvable="true"/>
模块C中Spring 配置文件中注入'c.properties',如下
<context:property-placeholder location="classpath:c.properties" order="3" ignore-unresolvable="false"/>
参考
关于<context:property-placeholder>的一个有趣现象
锁定老帖子 主题:关于<context:property-placeholder>的一个有趣现象