框架对org.springframework.beans.factory.config.PropertyPlaceholderConfigurer进行了扩展,对server.properties文件的加载过程进行封装。通过特殊的寻址方式,使配置文件与项目代码彻底分离,方便项目在不同环境的部署。同时也提供对属性的加解密功能。
主要功能:定位项目位置、找寻server.properties文件、属性加密
关键代码1 - 定位项目位置
private String getClassPathLocation() {
String classPathLocation = null;
// 查找classPath的路径
URL classPathURL = this.getClass().getClassLoader().getResource("");
// 如果取不到,尝试以config/empty.properties为目标文件查找,期望查找出jar包路径
if (classPathURL == null || classPathURL.getPath().endsWith("jar!/")) {
classPathURL = this.getClass().getClassLoader().getResource("config/empty.properties");
// 对jar包路径进行处理
String str = classPathURL.getPath();
System.err.println("包含empty.properties的jar包的路径径为-->" + str);
if (str.indexOf(".jar!") != -1) {
str = str.replace("file:", "");
int endPos = str.lastIndexOf(".jar!");
System.err.println("endPos-->" + endPos);
endPos = str.lastIndexOf("/", endPos);
System.err.println("endPos-->" + endPos);
classPathLocation = str.substring(0, endPos - 3);
} else {
System.err.println(str + "未找到.jar!关键字");
classPathLocation = str;
}
// 获取到URL
} else {
System.err.println("直接获取到classpath目录-->" + classPathURL.getPath());
classPathLocation = classPathURL.getPath();
}
return classPathLocation;
}
关键代码2 - 找寻server.properties文件
if (!isResourceExisted) {
// 依次往上级递归,查询配置文件是否存在
for (int level = 1; level <= CONFIG_PATH_LEVEL; level++) {
String confPath = assembleResourceDirLocation(classPathLocation, level);
String resourcePath = confPath + filename;
try {
location = new FileSystemResource(resourcePath);
InputStream f = location.getInputStream();
System.out.println("配置文件路径是: " + resourcePath);
// 载入的是war中的properties
logger.warn("配置文件路径是: " + resourcePath);
isResourceExisted = true;
// 如果找不到文件暂不处理,等遍历结束处理
break;
} catch (Exception ex) {
}
}
// 如果按服务器上的规范没有找到,则对开发环境的约定目录进行扫描
// 开发环境需要将server.properties文件放在src/test/resources/config/下面,保证测试用例能够访问到。
}
关键代码3 - 属性加密
(1)密钥文件生成
private void createKey(String confPath) throws FileNotFoundException, NoSuchAlgorithmException {
String keyFilePath = confPath + "/prop.key";
System.out.println("计算得出的密钥路径为:" + keyFilePath);
File keyFile = new File(keyFilePath);
if (keyFile.exists()) {
System.out.println("检测到密钥已存在。");
this.propKey = DESEncryptUtil.getKey(new FileInputStream(keyFile));
// 如果key文件不存在,则生成文件
} else {
this.propKey = DESEncryptUtil.createKey(keyFilePath);
}
}
(2)属性自动加密
if (key.endsWith(DES_PROP_SUFFIX)) {
// 如果当前属性值没有加密,则变成加密的,否则不用动
if (!value.startsWith("DES{")) {
value = "DES{"
+ DESEncryptUtil.doEncrypt(value.getBytes("UTF-8"),
propKey) + "}";
// 设置加密属性文件标识
doEncrypt = true;
// 生成新一行的加密串
line = key + "=" + value;
if (logger.isDebugEnabled()) {
logger.debug("encrypt property:" + key);
}
}
}
(3)属性解密
if (key.endsWith(DES_PROP_SUFFIX)) {
String obj = (String) newprops.get(key);
// 如果是加密属性,则应解密放在内存中,供spring配置文件使用
if (obj.startsWith("DES{")) {
String encryptVal = obj.substring(4, obj.length() - 1);
String originVal = new String(DESEncryptUtil.doDecrypt(encryptVal, propKey), "UTF-8");
props.remove(key);
props.setProperty(key, originVal);
} else {
// 如果是需要加密的属性,且没有加密,则需要加密后再回写properties文件
encrypteing = true;
}
}