`
wusuoya
  • 浏览: 630389 次
  • 性别: Icon_minigender_2
  • 来自: 成都
社区版块
存档分类
最新评论

关于<context:property-placeholder>的一个有趣现象

    博客分类:
  • SSH
 
阅读更多
先来看下A和B两个模块


A模块和B模块都分别拥有自己的Spring XML配置,并分别拥有自己的配置文件:

A模块

A模块的Spring配置文件如下:
Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8" ?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:p="http://www.springframework.org/schema/p" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> 
   <context:property-placeholder location="classpath*:conf/conf_a.properties"/> 
   <bean class="com.xxx.aaa.Bean1" 
          p:driverClassName="${modulea.jdbc.driverClassName}" 
          p:url="${modulea.jdbc.url}" 
          p:username="${modulea.jdbc.username}" 
          p:password="${modulea.jdbc.password}"/> 
</beans> 

其配置文件位于类路径conf/conf_a.properties中:
Xml代码  收藏代码
modulea.jdbc.driverClassName=com.mysql.jdbc.Driver 
modulea.jdbc.username=cartan 
modulea.jdbc.password=superman 
modulea.jdbc.url=jdbc:mysql://127.0.0.1:3306/modulea?useUnicode=true&characterEncoding=utf8 


B模块

B模块的Spring配置文件如下:
Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8" ?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:p="http://www.springframework.org/schema/p" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> 
   <context:property-placeholder location="classpath*:conf/conf_b.properties"/> 
   <bean class="com.xxx.bbb.Bean1" 
          p:driverClassName="${moduleb.jdbc.driverClassName}" 
          p:url="${moduleb.jdbc.url}" 
          p:username="${moduleb.jdbc.username}" 
          p:password="${moduleb.jdbc.password}"/> 
</beans> 

其配置文件位于类路径conf/conf_b.properties中:
Java代码  收藏代码
moduleb.jdbc.driverClassName=com.mysql.jdbc.Driver 
moduleb.jdbc.username=cartan 
moduleb.jdbc.password=superman 
moduleb.jdbc.url=jdbc:mysql://127.0.0.1:3306/modulea?useUnicode=true&characterEncoding=utf8 


问题来了

单独运行A模块,或单独运行B模块都是正常的,但将A和B两个模块集成后运行,Spring容器就启动不了了:

引用
Could not resolve placeholder 'moduleb.jdbc.driverClassName' in string value "${moduleb.jdbc.driverClassName}"



到底出了啥问题

随便搜索了一下,还发现很多人遇到这个问题,这个就是来自stackoverflow的问题:
http://stackoverflow.com/questions/7940452/spring-application-context-not-able-to-load-property-placeholder-properties

可惜啊,好像都没有人给出正确的解决。

那究竟是什么问题呢?也想了很久哦....终于回想起来了(写书时读过Spring源码),原来是Spring容器采用反射扫描的发现机制,在探测到Spring容器中有一个org.springframework.beans.factory.config.PropertyPlaceholderConfigurer的Bean就会停止对剩余PropertyPlaceholderConfigurer的扫描(Spring 3.1已经使用PropertySourcesPlaceholderConfigurer替代PropertyPlaceholderConfigurer了)。

而<context:property-placeholder/>这个基于命名空间的配置,其实内部就是创建一个PropertyPlaceholderConfigurer Bean而已。换句话说,即Spring容器仅允许最多定义一个PropertyPlaceholderConfigurer(或<context:property-placeholder/>),其余的会被Spring忽略掉(其实Spring如果提供一个警告就好了)。

拿上来的例子来说,如果A和B模块是单独运行的,由于Spring容器都只有一个PropertyPlaceholderConfigurer,因此属性文件会被正常加载并替换掉。如果A和B两模块集成后运行,Spring容器中就有两个PropertyPlaceholderConfigurer Bean了,这时就看谁先谁后了, 先的保留,后的忽略!因此,只加载到了一个属性文件,因而造成无法正确进行属性替换的问题。

咋解决呢?

定位问题需要9999元钱,解决问题只需要1元钱 。
属性文件加载在统一的地方做,不要分模块加载即可。

A模块a.xml:
Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8" ?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:p="http://www.springframework.org/schema/p" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> 
   <!--<context:property-placeholder location="classpath*:conf/conf_a.properties"/>--> 
   <bean class="com.xxx.aaa.Bean1" 
          p:driverClassName="${modulea.jdbc.driverClassName}" 
          p:url="${modulea.jdbc.url}" 
          p:username="${modulea.jdbc.username}" 
          p:password="${modulea.jdbc.password}"/> 
</beans> 


B模块b.xml:
Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8" ?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:p="http://www.springframework.org/schema/p" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> 
   <!--<context:property-placeholder location="classpath*:conf/conf_b.properties"/>--> 
   <bean class="com.xxx.bbb.Bean1" 
          p:driverClassName="${moduleb.jdbc.driverClassName}" 
          p:url="${moduleb.jdbc.url}" 
          p:username="${moduleb.jdbc.username}" 
          p:password="${moduleb.jdbc.password}"/> 
</beans> 


集成:
Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8" ?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:p="http://www.springframework.org/schema/p" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> 
   <context:property-placeholder location="classpath*:conf/conf*.properties"/> 
   <import resource="a.xml"/> 
   <import resource="b.xml"/> 
</beans> 


进一步思考

为什么啊?Spring为什么要这样呢?细想想是有道理的,一个项目或一个系统的配置应该放在一起,不宜分散。
这样才可以做到统一管控,否则到处都有配置,到底是加载哪个配置文件呢?有时你还会不小心让JAR中的Spring配置文件加载一个位于JAR中的属性文件,而外面有更改不了。如果Spring使用了这种机制,即使JAR包中的Spring配置文件使用<context:property-placeholder/>引用到JAR中的属性文件,只要你要外而的Spring配置文件中显示提供一个<context:property-placeholder/>指定另一个属性文件 ,就可以覆盖JAR中的默认配置了。

想了一想,Spring这样做是利大于弊的。
分享到:
评论

相关推荐

    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;时的坑

    主要介绍了Spring整合Mybatis使用&lt;context&gt;时的坑 的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下

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

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

    一个整合ssm框架的实例

    &lt;context:property-placeholder location="classpath:jdbc.properties"/&gt; &lt;!-- 配置数据库连接池 --&gt; &lt;bean id="dataSource" class=...

    OA项目SSH整合框架

    &lt;context:property-placeholder location="classpath:jdbc.properties" /&gt; &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt; &lt;property name=...

    轻量级高性能 RPC 框架 HRPC.zip

     &lt;context:property-placeholder location="classpath:system.properties"/&gt;  &lt;!--服务端配置--&gt;  &lt;bean id="rpcServer" class="com.yingjun.rpc.server.RPCServer"&gt;  &lt;constructor-arg name=...

    spring_MVC源码

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

    springmybatis

    请注意,这里面有一个方法名 selectUserByID 必须与 User.xml 里面配置的 select 的id 对应(&lt;select id="selectUserByID") 重写测试代码 程序代码 程序代码 public static void main(String[] args) { ...

    stdafx.h代码

    #include &lt;afxres.h&gt; // standard resource IDs #endif #ifndef __AFXCOLL_H__ #include &lt;afxcoll.h&gt; // standard collections #endif #ifdef _AFX_MINREBUILD #pragma component(minrebuild, off) #endif #...

    微软内部资料-SQL性能优化3

    This property is often called serializability. For example, a second transaction traversing the doubly linked list mentioned above would see the list before or after the insert, but it will see only ...

    ZendFramework中文文档

    3.2.2. 高级使用:持久一个 DbTable 结果对象 3.2.3. 高级用法示例 3.3. 摘要式认证 3.3.1. 简介 3.3.2. 规范(Specifics) 3.3.3. 身份(Identity) 3.4. HTTP 认证适配器 3.4.1. 简介 3.4.2. 设计回顾 ...

Global site tag (gtag.js) - Google Analytics