原文地址:https://blog.csdn.net/feiyu8607/article/details/8282893

Spring中PropertyPlaceholderConfigurer这个类,它是用来解析Java Properties属性文件值,并提供在spring配置期间替换使用属性值。接下来让我们逐渐的深入其配置。

基本的使用方法是:

<bean id="propertyConfigurerForAnalysis"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:/spring/include/dbQuery.properties</value>
</property>
</bean>

其中classpath是引用src目录下的文件写法。

当存在多个Properties文件时,配置就需使用locations了:(2)

<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/spring/include/jdbc-parms.properties</value>
<value>classpath:/spring/include/base-config.properties</value>
</list>
</property>
</bean>  

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

<bean id="propertyConfigurerForProject1"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="order" value="1" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:/spring/include/dbQuery.properties</value>
</list>
</property>
</bean> <bean id="propertyConfigurerForProject2"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="order" value="2" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:/spring/include/jdbc-parms.properties</value>
<value>classpath:/spring/include/base-config.properties</value>
</list>
</property>
</bean>

其中order属性代表其加载的顺序,如果没有设置就按照加载xml文件时的顺序,而ignoreUnresolvablePlaceholders为是否忽略不可解析的Placeholder,如果配置了多个PropertyPlaceholderConfigurer,则该属性必须设置且为true,否则propertyConfigurerForProject2的properties文件不会被加载.

至此你已经了解到了如何使用PropertyPlaceholderConfigurer,如何使用多个Properties文件,以及如何配置多个PropertyPlaceholderConfigurer来分解工程中分散的Properties文件。至于PropertyPlaceholderConfigurer还有更多的扩展应用,如属性文件加密解密等方法将在之后的博文中续写。

注意事项:
(1)如果上面的dbQuery.properties与jdbc-parms.properties文件中有相同的参数配置名称,dbQuery.properties中配置的参数值不会被后面的覆盖;
(2)如果jdbc-parms.properties,base-config.properties彼此有相同参数名配置,jdbc-parms.properties中的配置的值会被覆盖;

自定义扩展PropertyPlaceholderConfigurer实现

例如:配置文件的路径,需要动态确定的,就需要自己扩展PropertyPlaceholderConfigurer的实现,自己获取文件路径,load properties文件,然后将load后的properties加入PropertyPlaceholderConfigurer

package com.common.spring.ext;

import java.util.Properties;
import java.util.Set; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import com.common.exception.ApplicationException;
import com.common.util.GlobalProperties;
import com.common.util.PropertiesUtil; public class GollfPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer { public void setGollfPropFiles(Set<String> gollfPropFiles) {
String propPath = GlobalProperties.getProperty(GlobalProperties.PROPERTIES_FOLDER_PATH); //通过其他配置获取路径
String fileSeparator = System.getProperty("file.separator"); Properties properties = new Properties();
for (String gollfPropFile : gollfPropFiles) { String nodeName = System.getProperty("weblogic.Name");
gollfPropFile = gollfPropFile.replaceAll("\\[NODE_NAME\\]", nodeName); //NODE_NAME 是根据不同weblogic server确定 String file = propPath + fileSeparator + gollfPropFile; try {
logger.info("Loading properites file from " + file);
Properties prop = PropertiesUtil.loadProperties(file); //返回properties文件
logger.debug("Properties -> " + prop);
if(prop != null) {
properties.putAll(prop);
}
} catch (Exception e) {
logger.fatal(new ApplicationException("Properties file " + gollfPropFile +
" cannot be found. All related functionalities may be unavailable", e, true));
}
} this.setProperties(properties); //关键方法,调用的PropertyPlaceholderConfigurer中的方法,
//通过这个方法将自定义加载的properties文件加入spring中
} }
 <bean id="auditJmsProperties"
class="com.common.spring.ext.GollfPropertyPlaceholderConfigurer">
<property name="gollfPropFiles">
<set>
<value>[NODE_NAME]_jms.properties</value>
</set>
</property>
</bean>

PropertyPlaceholderConfigurer中加载properties文件时,实际调用的:org.springframework.core.io.support.PropertiesLoaderSupport中的mergeProperties

Spring源码

protected Properties mergeProperties() throws IOException {
Properties result = new Properties(); if (this.localOverride) {
// Load properties from file upfront, to let local properties override.
loadProperties(result);
} if (this.localProperties != null) {
for (Properties localProp : this.localProperties) {
//将用户自定义加载的属性值,与spring加载的合并
CollectionUtils.mergePropertiesIntoMap(localProp, result);
}
} if (!this.localOverride) {
// Load properties from file afterwards, to let those properties override.
loadProperties(result);
} return result;
}

将多个properties文件中的配置加载以后合并成一个Properties对象返回.
上面的this.setProperties(properties)方法,就是设置localProperties的引用,localProperties不为空的话,将用户自定义加载的properties属性合并到Spring加载的result Properties对象中
localOverride参数:为true的话,表示用户自定义加载的属性值覆盖spring系统加载的,如果同名的话.

自定义使用注意:用户自定义方法的调用务必在spring 初始化调用PropertyPlaceholderConfigurer的mergeProperties()方法之前调用,否则配置文件就没有合并.一般就set值的时候调用.

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

spring提供了一个PropertyPlaceholdConfigurer的 beanFactory后置处理器。可以将Bean配置的部分内容放到 属性文件 中,可以在Bean配置文件里使用形式为 ${var}的变量,PropertyPlaceholdConfigurer从属性文件里加载属性,并使用这些属性来替换变量。

以配置数据库连接字符串信息为例,配置如下:

<!-- 引入配置文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties" />
</bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${maxWait}"></property>
</bean>

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

使用spring的PropertyPlaceholderConfigurer加密properties文件中的属性

一、背景

处于安全考虑需要对.properties中的数据库用户名与密码等敏感数据进行加密。项目中使用了Spring3框架统一加载属性文件,所以最好可以干扰这个加载过程来实现对.properties文件中的部分属性进行加密。

属性文件中的属性最初始时敏感属性值可以为明文,程序第一次执行后自动加密明文为密文。

二、问题分析

  1. 扩展PropertyPlaceholderConfigurer最好的方式就是编写一个继承该类的子类。
  2. 外部设置locations时,记录全部locations信息,为加密文件保留属性文件列表。重写setLocations与setLocation方法(在父类中locations私有)
  3. 寻找一个读取属性文件属性的环节,检测敏感属性加密情况。对有已有加密特征的敏感属性进行解密。重写convertProperty方法来实现。
  4. 属性文件第一次加载完毕后,立即对属性文件中的明文信息进行加密。重写postProcessBeanFactory方式来实现。
三、代码实现
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- 加密 -->
<property name="locations">
<list>
<value>classpath:db.properties</value>
</list>
</property>
<!-- 声明需要加密的属性 -->
<property name="encryptedProps">
<set>
<value>db.jdbc.username</value>
<value>db.jdbc.password</value>
<value>db.jdbc.url</value>
</set>
</property>
</bean>
package com.sgfm.test;

import com.sgfm.base.des.DESEncryptUtil;

public class Test {
private static final String SEC_KEY = "@^_^123aBcZ*"; // 主密钥
private static final String ENCRYPTED_PREFIX = "{";// 默认加密前缀
private static final String ENCRYPTED_SUFFIX = "}";// 默认加密后缀 public static void main(String[] args) throws Exception {
DESEncryptUtil dec = new DESEncryptUtil();
String encryptStr = dec.encrypt("tcp://192.168.10.242:61616", SEC_KEY);// 加密
String decryptStr = dec.decrypt("1B7328C79D9D5BC37E0636947EFEECD6E1459B4260497E31000754134655A350", SEC_KEY);// 解密 System.out.println("加密内容:" + encryptStr);
System.out.println("解密内容:" + decryptStr);
}
}
db.jdbc.driver=com.mysql.jdbc.Driver
db.jdbc.url=jdbc:mysql://localhost:3306/noah?useUnicode=true&characterEncoding=utf8
db.jdbc.username=noah
db.jdbc.password=noah
db.jdbc.driver=com.mysql.jdbc.Driver
db.jdbc.url=Encrypted:{e5ShuhQjzDZrkqoVdaO6XNQrTqCPIWv8i_VR4zaK28BrmWS_ocagv3weYNdr0WwI}
db.jdbc.username=Encrypted:{z5aneQi_h4mk4LEqhjZU-A}
db.jdbc.password=Encrypted:{v09a0SrOGbw-_DxZKieu5w}

Spring PropertyPlaceholderConfigurer 自定义扩展的更多相关文章

  1. 基于Spring的可扩展Schema进行开发自定义配置标签支持

    一.背景 最近和朋友一起想开发一个类似alibaba dubbo的功能的工具,其中就用到了基于Spring的可扩展Schema进行开发自定义配置标签支持,通过上网查资料自己写了一个demo.今天在这里 ...

  2. Spring 实现自定义 bean 的扩展

    Spring mvc 提供了扩展 xml 的机制,用来编写自定义的 xml bean ,例如 dubbo 框架,就利用这个机制实现了好多的 dubbo bean,比如 <dubbo:applic ...

  3. Spring中自定义Schema扩展机制

    一.前言 Spring 为基于 XML 构建的应用提供了一种扩展机制,用于定义和配置 Bean. 它允许使用者编写自定义的 XML bean 解析器,并将解析器本身以及最终定义的 Bean 集成到 S ...

  4. 聊聊spring的那些扩展机制

    1.背景 慎入:本文将会有大量代码出入. 在看一些框架源码的时候,可以看见他们很多都会和Spring去做结合.举个例子dubbo的配置: 很多人其实配置了也就配置了,没有去过多的思考:为什么这么配置s ...

  5. 使用Spring Session实现Spring Boot水平扩展

    小编说:本文使用Spring Session实现了Spring Boot水平扩展,每个Spring Boot应用与其他水平扩展的Spring Boot一样,都能处理用户请求.如果宕机,Nginx会将请 ...

  6. spring AOP自定义注解方式实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

  7. spring AOP自定义注解 实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

  8. Spring Security 自定义登录认证(二)

    一.前言 本篇文章将讲述Spring Security自定义登录认证校验用户名.密码,自定义密码加密方式,以及在前后端分离的情况下认证失败或成功处理返回json格式数据 温馨小提示:Spring Se ...

  9. 缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制

    背景 在 Dubbo 中,可以使用 XML 配置相关信息,也可以用来引入服务或者导出服务.配置完成,启动工程,Spring 会读取配置文件,生成注入 相关 Bean.那 Dubbo 如何实现自定义 X ...

随机推荐

  1. 啥是 MySQL 事务隔离级别?

    之前发过一篇文章,简单了解 MySQL 中相关的锁,里面提到了,如果我们使用的 MySQL 存储引擎为 InnoDB ,并且其事务隔离级别是 RR 可重复读的话,是可以避免幻读的. 但是没想到,都 1 ...

  2. odoo12里面的RPC【远程过程调用】

    odoo的RPC有两种:RPC API:1.xml-rpc                                                      2.json-rpc 案例   x ...

  3. maven 标签 关于<import>标签

      标签用途:在dependecyManagement元素下用,合并此import标签上级dependency的groupId和artid中指向依赖的dependecyManagement内容   标 ...

  4. K-Fold 交叉验证

    转载--原文地址 www.likecs.com 1.K-Fold 交叉验证概念 在机器学习建模过程中,通行的做法通常是将数据分为训练集和测试集.测试集是与训练独立的数据,完全不参与训练,用于最终模型的 ...

  5. C语言复习(一)

    类型为void*的指针代表对象的地址,而不是类型 如果需要使用另一个源文件中定义的变量,那么只需要在定义变量前加上extern关键字 ex: extern int x;//x在其他文件中定义 左值表达 ...

  6. HotSpot 对象

    概述 当Java虚拟机遇到一条字节码new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用, 并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那必须先执行相 ...

  7. tomcat启动时启动窗口出现乱码一招搞定

    先来看看问题(图示),在tomcat的启动窗口打印的启动信息中包含了大量的中文乱码,虽然这些对tomcat本身的使用没有任何影响,但却非常碍眼,影响视觉效果! tomcat启动时启动窗口出现乱码的解决 ...

  8. 普通类中获取spring容器中的javabean对象

    spring提供了一系列的*Aware 接口,用于获取相应的对象,进行一系列的对象设置操作,此处实现ApplicationContextAware来获取ApplicationContext. 其他Aw ...

  9. AQS学习(一)自旋锁原理介绍(为什么AQS底层使用自旋锁队列?)

    1.什么是自旋锁? 自旋锁作为锁的一种,和互斥锁一样也是为了在并发环境下保护共享资源的一种锁机制.在任意时刻,只有一个执行单元能够获得锁. 互斥锁通常利用操作系统提供的线程阻塞/唤醒机制实现,在争用锁 ...

  10. .NET 6 预览版 7:新功能已完成 ,将专注于改进

    .NET 团队的项目经理 Richard Lander在宣布 .NET 6 Preview 7 时说:"这是 .NET 预览的又一季的结束.", 中文翻译:.NET 6 预览版 7 ...