转自:https://hbiao68.iteye.com/blog/2031006

1.Spring的框架中,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer类可以将.properties(key/value形式)文件中一些动态设定的值(value),在XML中替换为占位该键($key$)的值,.properties文件可以根据客户需求,自定义一些相关的参数,这样的设计可提供程序的灵活性。

2.在Spring中,使用PropertyPlaceholderConfigurer可以在XML配置文件中加入外部属性文件,当然也可以指定外部文件的编码,如:

  1. <bean id="propertyConfigurerForAnalysis" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  2. <property name="location">
  3. <value>classpath:/spring/include/dbQuery.properties</value>
  4. </property>
  5. <property name="fileEncoding">
  6. <value>UTF-8</value>
  7. </property>
  8. </bean>

其中classpath是引用src目录下的文件写法,当存在多个Properties文件时,配置就需使用locations了:

  1. <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  2. <property name="locations">
  3. <list>
  4. <value>classpath:/spring/include/jdbc-parms.properties</value>
  5. <value>classpath:/spring/include/base-config.properties</value>
  6. <value>classpath*:config/jdbc.properties</value>
  7. </list>
  8. </property>
  9. </bean>
  1. <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  2. <property name="location">
  3. <value>classpath:hb.properties</value>
  4. <value>/WEB-INF/config/project/project.properties</value>
  5. </property>
  6. </bean>

接下来我们要使用多个PropertyPlaceholderConfigurer来分散配置,达到整合多工程下的多个分散的Properties文件,其配置如下

  1. <bean id="propertyConfigurerForProject2" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  2. <property name="order" value="2" />
  3. <property name="ignoreUnresolvablePlaceholders" value="true" />
  4. <property name="locations">
  5. <list>
  6. <value>classpath:/spring/include/jdbc-parms.properties</value>
  7. <value>classpath:/spring/include/base-config.properties</value>
  8. </list>
  9. </property>
  10. </bean>

其中order属性代表其加载顺序,而ignoreUnresolvablePlaceholders为是否忽略不可解析的Placeholder,如配置了多个PropertyPlaceholderConfigurer,则需设置为true

3.譬如,jdbc.properties的内容为:

  1. jdbc.driverClassName=com.mysql.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost/mysqldb?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=round;
  3. jdbc.username=root
  4. jdbc.password=123456

备注:一定要在properties文件中&写为&amp;因为在xml文件中不识别&,必须是&amp

4.那么在spring配置文件中,我们就可以这样写:

  1. <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  2. <property name="locations">
  3. <list>
  4. <value>classpath: conf/sqlmap/jdbc.properties </value>
  5. </list>
  6. </property>
  7. </bean>
  8. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  9. <property name="driverClassName" value="${jdbc.driverClassName}" />
  10. <property name="url" value="${jdbc.url}" />
  11. <property name="username" value="${jdbc.username}" />
  12. <property name="password" value="${jdbc.password}" />
  13. </bean>

这样,一个简单的数据源就设置完毕了。可以看出:PropertyPlaceholderConfigurer起的作用就是将占位符指向的数据库配置信息放在bean中定义的工具

查看源代码,可以发现,locations属性定义在PropertyPlaceholderConfigurer的祖父类PropertiesLoaderSupport中,而location只有setter方法。类似于这样的配置,在spring的源程序中很常见的。

PropertyPlaceholderConfigurer如果在指定的Properties文件中找不到你想使用的属性,它还会在Java的System类属性中查找。
我们可以通过System.setProperty(key, value)或者java中通过-Dnamevalue来给Spring配置文件传递参数。

我们还可以使用注解的方式实现,如:<context:property-placeholder location="classpath:jdbc.properties" />,效果跟PropertyPlaceholderConfigurer是一样的。

原理分析

PropertyPlaceholderConfigurer类是如何做到xml配置的bean的配置熟悉的运行时替换的呢?这个离不开Spring框架提供的许多扩展点。这个类依赖的扩展点就是BeanFactoryPostProcessors见下面的类继承图:

BeanFactoryPostProcessors类有一个方法,提供了在Bean创建前对Bean的Definition进行处理的钩子机制。

 //在Bean初始化前被调用(例如在InitializingBean的afterPropertiesSet前)
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

从上面的继承图我们知道PropertyPlaceholderConfigurer继承自类PropertyResourceConfigurer, 而该类实现了接口BeanFactoryPostProcessors

 public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
implements BeanFactoryPostProcessor, PriorityOrdered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
Properties mergedProps = mergeProperties(); // Convert the merged properties, if necessary.
convertProperties(mergedProps); // Let the subclass process the properties.
processProperties(beanFactory, mergedProps);
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
protected abstract void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
throws BeansException;
}

我们的主角PropertyPlaceholderConfigurer实现了父类中的方法processProperties, 在该类中对xml配置文件中的展位符进行替换处理

 /**
* Visit each bean definition in the given bean factory and attempt to replace ${...} property
* placeholders with values from the given properties.
*/
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
throws BeansException { StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
doProcessProperties(beanFactoryToProcess, valueResolver);
} protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) { BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
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);
}

这样就解开了Spring中xml配置文件中占位符的替换魔法功能。

现在想一下,如果我们的配置文件中对某些属性进行了加密,这时再使用 PropertyPlaceholderConfigurer 读取配置文件我们想要加密前的内容该怎么办?

答案就是重写 PropertyPlaceholderConfigurer。除了数据库的配置信息我们放在配置文件,然后可以通过 druid 进行加解密。但是配置的邮箱信息呢?

这时重写它就显得很有必要。PropertyPlaceholderConfigurer起的作用就是将占位符指向的数据库配置信息放在bean中定义的工具。

下面来看一个通过 PropertyPlaceholderConfigurer读取加解密配置文件的案例:

 package com.xttblog.plugin;
import com.zheng.common.util.AESUtil;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
//支持加密配置文件插件
public class EncryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
private String[] propertyNames = {
"master.jdbc.password", "slave.jdbc.password", "generator.jdbc.password", "master.redis.password"
};
//解密指定propertyName的加密属性值
@Override
protected String convertProperty(String propertyName, String propertyValue) {
for (String p : propertyNames) {
if (p.equalsIgnoreCase(propertyName)) {
return AESUtil.AESDecode(propertyValue);
}
}
return super.convertProperty(propertyName, propertyValue);
}
}

我们只需重写 PropertyPlaceholderConfigurer 类的 convertProperty 方法即可,然后在该方法中实现解密工作。

spring 配置文件 获取变量(PropertyPlaceholderConfigurer)的更多相关文章

  1. 【转】spring管理属性配置文件properties——使用PropertiesFactoryBean|spring管理属性配置文件properties——使用PropertyPlaceholderConfigurer

     spring管理属性配置文件properties--使用PropertiesFactoryBean 对于属性配置,一般采用的是键值对的形式,如:key=value属性配置文件一般使用的是XXX.pr ...

  2. Spring使用环境变量控制配置文件加载

    项目中需要用到很多配置文件,不同环境的配置文件是不一样的,因此如果只用一个配置文件,势必会造成配置文件混乱,这里提供一种利用环境变量控制配置文件加载的方法,如下: 一.配置环境变量 如果是window ...

  3. 监听器如何获取Spring配置文件(加载生成Spring容器)

    Spring容器是生成Bean的工厂,我们在做项目的时候,会用到监听器去获取spring的配置文件,然后从中拿出我们需要的bean出来,比如做网站首页,假设商品的后台业务逻辑都做好了,我们需要创建一个 ...

  4. Spring使用环境变量控制配置文件加载(转)

    项目中需要用到很多配置文件,不同环境的配置文件是不一样的,因此如果只用一个配置文件,势必会造成配置文件混乱,这里提供一种利用环境变量控制配置文件加载的方法,如下: 一.配置环境变量 如果是window ...

  5. 监听器如何获取Spring配置文件

    我们在做项目的时候,会用到监听器去获取spring的配置文件,然后从中拿出我们需要的bean出来,比如做网站首页,假设商品的后台业务逻辑都做好了,我们需要创建一个监听器,在项目启动时将首页的数据查询出 ...

  6. spring boot中配置文件中变量的引用

    配置文件中 变量的自身引用 ${名称} java文件中引用:非静态变量 之间在变量上面注释@Value("${名称}")  静态变量 在set方法上注释@Value("$ ...

  7. Spring配置文件外部化配置及.properties的通用方法

    摘要:本文深入探讨了配置化文件(即.properties)的普遍应用方式.包括了Spring.一般的.远程的三种使用方案. 关键词:.properties, Spring, Disconf, Java ...

  8. spring源码分析系列 (5) spring BeanFactoryPostProcessor拓展类PropertyPlaceholderConfigurer、PropertySourcesPlaceholderConfigurer解析

    更多文章点击--spring源码分析系列 主要分析内容: 1.拓展类简述: 拓展类使用demo和自定义替换符号 2.继承图UML解析和源码分析 (源码基于spring 5.1.3.RELEASE分析) ...

  9. spring配置文件引入properties文件:<context:property-placeholder>标签使用总结

    一.问题描述: 1.有些参数在某些阶段中是常量,比如: (1)在开发阶段我们连接数据库时的连接url.username.password.driverClass等 (2)分布式应用中client端访问 ...

随机推荐

  1. 004.RAID删除

    一 卸载RAID [root@kauai ~]# umount /dev/md0 #卸载挂载点 二 停止RAID设备 [root@kauai ~]# mdadm -S /dev/md0 #停用RAID ...

  2. 多线程学习笔记六之并发工具类CountDownLatch和CyclicBarrier

    目录 简介 CountDownLatch 示例 实现分析 CountDownLatch与Thread.join() CyclicBarrier 实现分析 CountDownLatch和CyclicBa ...

  3. luogu [TJOI2007]线段

    题目链接 luogu [TJOI2007]线段 题解 dp[i][0/1]第i行在左/右端点的最短路 瞎转移 代码 #include<bits/stdc++.h> using namesp ...

  4. BZOJ2924 : [Poi1998]Flat broken lines

    首先旋转坐标系 $x'=x-y$ $y'=-x-y$ 则对于一个点,它下一步可以往它左上角任意一个点连线. 根据Dilworth定理,答案=这个偏序集最长反链的长度. 设f[i]为到i点为止的最长反链 ...

  5. $.ajax 方法参数总是记不住,在这里记录一下

    jquery中的ajax方法参数总是记不住,这里记录一下. 1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为String类型的参数,请求方式(p ...

  6. centos 7 安装 rvm 超时

    关于 rvm  建议没有变成基础的朋友不要选择这种方式安装   不然很有可能到 对ruby很感兴趣想学到放弃的 因为ruby实在是太麻烦 太麻烦  你会遇到各种各样的问题   我之前安装过一次rvm ...

  7. myeclipse优化 Maven

    1.禁用myeclipse updating indexes MyEclipse 总是不停的在 Update index,研究发现Update index...是Maven在下载更新,但很是影响mye ...

  8. tapd

    注册公司-TAPD   https://www.tapd.cn/registers/register_company_finish/maolingzhi@meizu.com?type=email_va ...

  9. STM32的PWM输入模式设置并用DMA接收数据

    参考 :STM32输入捕获模式设置并用DMA接收数据 PWM input mode This mode is a particular case of input capture mode. The ...

  10. Linux网络编程socket选项之SO_LINGER,SO_REUSEADDR

    from http://blog.csdn.net/feiyinzilgd/article/details/5894300 Linux网络编程中,socket的选项很多.其中几个比较重要的选项有:SO ...