转:http://stamen.iteye.com/blog/1926166

先来看下A和B两个模块

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

A模块 

A模块的Spring配置文件如下:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:p="http://www.springframework.org/schema/p"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
  7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
  8. <context:property-placeholder location="classpath*:conf/conf_a.properties"/>
  9. <bean class="com.xxx.aaa.Bean1"
  10. p:driverClassName="${modulea.jdbc.driverClassName}"
  11. p:url="${modulea.jdbc.url}"
  12. p:username="${modulea.jdbc.username}"
  13. p:password="${modulea.jdbc.password}"/>
  14. </beans>

其配置文件位于类路径conf/conf_a.properties中:

  1. modulea.jdbc.driverClassName=com.mysql.jdbc.Driver
  2. modulea.jdbc.username=cartan
  3. modulea.jdbc.password=superman
  4. modulea.jdbc.url=jdbc:mysql://127.0.0.1:3306/modulea?useUnicode=true&characterEncoding=utf8

B模块 

B模块的Spring配置文件如下:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:p="http://www.springframework.org/schema/p"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
  7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
  8. <context:property-placeholder location="classpath*:conf/conf_b.properties"/>
  9. <bean class="com.xxx.bbb.Bean1"
  10. p:driverClassName="${moduleb.jdbc.driverClassName}"
  11. p:url="${moduleb.jdbc.url}"
  12. p:username="${moduleb.jdbc.username}"
  13. p:password="${moduleb.jdbc.password}"/>
  14. </beans>

其配置文件位于类路径conf/conf_b.properties中:

  1. moduleb.jdbc.driverClassName=com.mysql.jdbc.Driver
  2. moduleb.jdbc.username=cartan
  3. moduleb.jdbc.password=superman
  4. 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:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:p="http://www.springframework.org/schema/p"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
  7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
  8. <!--<context:property-placeholder location="classpath*:conf/conf_a.properties"/>-->
  9. <bean class="com.xxx.aaa.Bean1"
  10. p:driverClassName="${modulea.jdbc.driverClassName}"
  11. p:url="${modulea.jdbc.url}"
  12. p:username="${modulea.jdbc.username}"
  13. p:password="${modulea.jdbc.password}"/>
  14. </beans>

B模块b.xml:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:p="http://www.springframework.org/schema/p"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
  7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
  8. <!--<context:property-placeholder location="classpath*:conf/conf_b.properties"/>-->
  9. <bean class="com.xxx.bbb.Bean1"
  10. p:driverClassName="${moduleb.jdbc.driverClassName}"
  11. p:url="${moduleb.jdbc.url}"
  12. p:username="${moduleb.jdbc.username}"
  13. p:password="${moduleb.jdbc.password}"/>
  14. </beans>

集成:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:p="http://www.springframework.org/schema/p"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
  7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
  8. <context:property-placeholder location="classpath*:conf/conf*.properties"/>
  9. <import resource="a.xml"/>
  10. <import resource="b.xml"/>
  11. </beans>

进一步思考 

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

想了一想,Spring这样做是利大于弊的。

关于<context:property-placeholder>的一个有趣现象的更多相关文章

  1. Python有趣现象(不定时更新)

    1.list中extend方法有趣现象 1.1 List+=Str 与 List.extend(Str) list1 = [11,2,45] str1 = 'Michael' list1.extend ...

  2. 关于Java中编码集的有趣现象和解释

    这是在整理另一篇博客的时候发现的一个有趣的现象,是这样描述的:我们都知道Java默认使用的是UniCode编码集,我们也知道char类型占用两个字节.所以奇怪的现象又发生了(见代码): @Test p ...

  3. 【小贴士】关于transitionEnd/animate的一个有趣故事

    前言 在很久之前,我们项目有一个动画功能,功能本身很简单,便是典型的右进左出,并且带动画功能 以当时来说,虽然很简单,但是受限于框架本身的难度,就直接使用了CSS3的方式完成了功能 当时主要使用tra ...

  4. 一个有趣的SQL Server 层级汇总数据问题

        看SQL Server大V宋大侠的博客文章,发现了一个有趣的sql server层级汇总数据问题.          具体的问题如下:     parent_id emp_id emp_nam ...

  5. 一个有趣的模拟光照的shader

    一个有趣的模拟光照的shader(类似法线贴图) http://www.cnblogs.com/flytrace/p/3395911.html -----  可否用于需UI中需要加灯的模型.

  6. 一个有趣的 SQL 查询(查询7天连续登陆)

    一个有趣的 SQL 查询 一个朋友有这样一个SQL查询需求: 有一个登录表(tmp_test),包含用户ID(uid)和登录时间(login_time).表结构如下: . row ********** ...

  7. 另一个有趣的Captcha 网站

    今天在一个网站注册时又发现了一个有趣的Captcha形式.给你一个翻转的图片,然后让你拽下面的slide bar让它回到正常的位置,很有趣.下面是提供这个Captcha的网站. minteye – s ...

  8. dubbo debug过程中一个有趣的问题

    最近在debug dubbo代码过程中遇到的很有趣的问题 我们都知道dubbo ReferenceBean是消费者的spring bean包装,为了查一个consumer端的问题,在Reference ...

  9. 一个有趣的小例子,带你入门协程模块-asyncio

    一个有趣的小例子,带你入门协程模块-asyncio 上篇文章写了关于yield from的用法,简单的了解异步模式,[https://www.cnblogs.com/c-x-a/p/10106031. ...

随机推荐

  1. Git学习之路(3)-提交文件到三个区

    ▓▓▓▓▓▓ 大致介绍 年过的差不多了,开始学习!小白学Git(持续更新) Git有三个工作区域: ◆ 工作区(Working Directory) ◆ 暂存区(Stage) ◆ 版本库(Reposi ...

  2. 【Unity3d游戏开发】浅谈UGUI中的Canvas以及三种画布渲染模式

    一.Canvas简介 Canvas画布是承载所有UI元素的区域.Canvas实际上是一个游戏对象上绑定了Canvas组件.所有的UI元素都必须是Canvas的自对象.如果场景中没有画布,那么我们创建任 ...

  3. java版二叉树算法实现

    import java.util.ArrayList; class BinaryTree { private static class TreeNode { int data; TreeNode le ...

  4. 使用nat方式解决虚拟机联网问题

    本文全文参考:http://jingyan.baidu.com/album/4e5b3e1957979d91901e24f1.html?picindex=1,谢谢 对于很多的linux初学者来说,最开 ...

  5. vs2010入门程序和出错问题解决方案

    本篇文章分两个部分: 第一,如何建立一个Helloword工程 1.打开Vs2010新建项目 2.选择Visual C++>>Win32>>Win32控制台应用程序,输入项目名 ...

  6. docker - 容器里安装mysql

    在docker中安装mysql ubuntu官方镜像是精简的ubuntu系统,很多软件和库没有安装,所以直接安装mysql的话依赖较多,建议直接从源码编译安装mysql 通过命令行安装 先启动一个容器 ...

  7. Java ArrayList小程序理解

    package Collection; import java.util.ArrayList; import java.util.Iterator; //import javax.xml.crypto ...

  8. 如何用js实现自适应,原来只是几行代码的事(╯‵□′)╯︵┻━┻

    在javascript写下如下几行:   (function (doc, win, undefined) {            var docEl = doc.documentElement,   ...

  9. 常用php时间函数用法汇总

    1.设置时区的方法: php5后都要自己设置时区,要么修改php.ini的设置,要么在代码里修改. 在PHP.INI中设置时区 date.timezone = PRC 在代码中设置时区 1 date_ ...

  10. 在Angular中,如果权限值是异步请求所得,如何将其设置为HTTP请求头的Authorization?

    遇到此问题的背景:项目需要实现单点登录,在前后端分离的前提下,前台如何保存token值成为了一个问题.想到的解决方案是,将token值统一存到一个前端程序,其他的前端程序去这个前端程序去取token( ...