原文地址: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. MongoDB 基础学习

    1.MongoDB 概念解析 SQL术语/概念 MongoDB术语/概念 解释/说明 database database 数据库 table collection 数据库表/集合 row docume ...

  2. 【贪心】数列分段Section I luogu-1181

    题目描述 对于给定的一个长度为\(N\)的正整数数列\(A_i\),现要将其分成连续的若干段,并且每段和不超过\(M\)(可以等于\(M\)),问最少能将其分成多少段使得满足要求. 分析 简单思考一下 ...

  3. ELK:match 的底层转换

    在ES中,执行match搜索的时候,ES底层通常都会对搜索条件进行底层转换,来实现最终的搜索结果.如: GET /student/java/_search { "query": { ...

  4. py3射击小游戏

    关于py3面向对象的小Demo,欢迎 交流. class Person(object):#声明人类 def __init__(self,name): self.name = name self.gun ...

  5. 深入刨析tomcat 之---第4篇 tomcat4.0连接池 实现原理

    writedby 张艳涛

  6. 开机时自动启动的AutoHotkey脚本 2019年07月08日19时06分

    ;;; 开机时自动启动的AutoHotkey脚本;; 此脚本修改时间 2019年06月18日20时48分;; 计时器创建代码段 ------------------------------------ ...

  7. Jenkins自动化部署最完整教程

    1.概述 Jenkins 是一个可扩展的持续集成引擎.主要用于持续.自动地构建/测试软件项目.监控一些定时执行的任务.Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行 ...

  8. 3个月零基础入门Python+数据分析,详细时间表+计划表分享

    ​大家好,我是白云. 今天想给大家分享的是三个月零基础入门数据分析学习计划.有小伙伴可能会说,英语好像有点不太好,要怎么办?所以今天我给大家分享的资源呢就是对国内的小伙伴很友好,还附赠大家一份三个月学 ...

  9. http笔记随笔

    1.HTTP (HyperText Transfer Protocol)超文本传输协议(80端口) 1.规定浏览器和服务器之间相互通信的规则 2.万维网交换信息的基础 3.允许将HTML文档从Web服 ...

  10. XCTF-Web进阶-upload1

    显然是让我们上传文件,思路当然是上传一个木马文件,然后通过蚁剑连接查看目录获取flag. 但是当我们想要上传php文件的时候会出现弹窗,并且连"上传"按钮都被禁用了. ext = ...