在 Spring 中,使用 PropertyPlaceholderConfigurer 可以在 XML 配置文件中加入外部属性文件,当然也可以指定外部文件的编码。PropertyPlaceholderConfigurer 可以将上下文(配置文 件)中的属性值放在另一个单独的标准 java Properties 文件中。在 XML 文件中用 ${key} 替换指定的 properties 文件中的值。这样的话,只需要对 properties 文件进行修改,而不用对 XML 配置文件进行修改。
PropertyPlaceholderConfigurer 是个 bean 工厂后置处理器的实现,也就是 BeanFactoryPostProcessor 接口的一个实现。源码实现如下:
(1)编写 db.properties 属性文件
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true jdbc.username=root jdbc.password=aaaaaa
(2)在 xml 中引入外部属性文件,即 .properties 文件。如果引单个文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:context="https://www.springframework.org/schema/context" xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.hxstrive"/> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:db.properties</value> </list> </property> </bean> </beans>
如果引多个文件,如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:context="https://www.springframework.org/schema/context" xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.hxstrive"/> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:db.properties</value> <value>classpath:db2.properties</value> <value>classpath:db3.properties</value> </list> </property> </bean> </beans>
引入外部文件后,就可以在 xml 中用 ${key} 替换指定的 properties 文件中的值,通常项目中都会将 jdbc 的配置放在 properties 文件中。如下:
<!-- 配置dbcp数据源 --> <bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean>
在启动容器时,初始化 bean 时,${key} 就会替换成 properties 文件中的值。
为了简化 PropertyPlaceholderConfigurer 的使用,Spring提供了<context:property-placeholder/>元素,启用它后,开发者便不用配置 PropertyPlaceholderConfigurer 对象了。
(1)编写 db.properties 属性文件
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true jdbc.username=root jdbc.password=aaaaaa
(2)使用 <context:property-placeholder/> 配置属性文件的位置,如下:
<!-- 数据库配置文件位置 --> <context:property-placeholder location="classpath:db.properties" />
PropertyPlaceholderConfigurer 内置的功能非常丰富,如果它未找到 ${xxx} 中定义的 xxx 键,它还会去 JVM 系统属性(System.getProperty())和环境变量(System.getenv())中寻找。通过启用 systemPropertiesMode 和searchSystemEnvironment 属性,开发者能够控制这一行为。<context:property-placeholder/> 大大的方便了我们数据库的配置,这样就可以为 spring 配置的 bean 的属性设置值了。如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:context="https://www.springframework.org/schema/context" xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.hxstrive"/> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="searchSystemEnvironment" value="true" /> <property name="systemPropertiesMode" value="1"/> <property name="locations"> <list> <value>classpath:db.properties</value> </list> </property> </bean> </beans>
(3)配置bean的属性
<!-- 配置dbcp数据源 --> <bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean>
注:spring 容器中最多只能定义一个 <context:property-placeholder/>,否则会报错:Could not resolve placeholder XXX。如果我们想引入多个属性文件怎么办呢?可以使用通配符:<context:property-placeholder location="classpath*:conf*.properties"/>
自定义 PropertyPlaceholderConfigurer 非常简单,需要继承 PropertyPlaceholderConfigurer 类,并且重写 processProperties() 方法。例如:
package com.huangx.spring4.rewrite; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import java.util.HashMap; import java.util.Map; import java.util.Properties; /** * 自定义 PropertyPlaceholderConfigurer * @author administrator */ public class MyPropertyPlaceholder extends PropertyPlaceholderConfigurer { private static Map<String,String> propertyMap; @Override protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { super.processProperties(beanFactoryToProcess, props); propertyMap = new HashMap<String, String>(); for (Object key : props.keySet()) { String keyStr = key.toString(); String value = props.getProperty(keyStr); propertyMap.put(keyStr, value); System.out.println(keyStr + "=" + value); } } // 自定义一个方法,即根据 key拿属性值,方便 java 代码中取属性值 public static String getProperty(String name) { return propertyMap.get(name); } }
在创建 bean 时就会调用 processProperties() 方法,属性文件中设置的键值对已经全部放到了参数 Properties 中,怎么使用这些值,需要根据实际业务需要。
接下来,我们就可以在 XML 中配置使用我们自定义的 PropertyPlaceholderConfigurer 类。如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:context="https://www.springframework.org/schema/context" xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.huangx.spring4"/> <bean class="com.huangx.spring4.rewrite.MyPropertyPlaceholder"> <property name="searchSystemEnvironment" value="true" /> <property name="systemPropertiesMode" value="1"/> <property name="locations"> <list> <value>classpath:props/db.properties</value> </list> </property> </bean> </beans>