框架通过对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 - 属性加解密
当属性名以“.des”结尾时,在系统运行后会自动进行加密,以增强系统的安全性。加密后的属性值如下:
bus.mysql.password.des=DES{4A49DFF9505B17E7458973381D8C26B0}
(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; }}