• spring系列之自定义扩展PropertyPlaceHolderConfigurer


    spring系列之自定义扩展PropertyPlaceHolderConfigurer

    目录

    spring系列之自定义扩展PropertyPlaceHolderConfigurer


     

     

     

    本文章向大家介绍spring系列之自定义扩展PropertyPlaceHolderConfigurer,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

     

     

     

    一、PropertyPlaceHolderConfigurer介绍

    主要用于将一些配置信息移出xml文件,移到至properties文件

    二、拓展使用

    1、将porperties内容设置成java全局可读

    思路:spring启动的时候会将properties加载至其指定缓存机制,可利用其加载机制,在读取properties时,保存一份至变量,对外提供访问接口。

    1.1 创建PropertyPlaceHolderConfigurer的子类,代码如下CustomPropertyPlaceConfigurer

    1. private Map ctxPropertiesMap;
    2. @Override
    3. protected void processProperties(
    4. ConfigurableListableBeanFactory beanFactoryToProcess,
    5. Properties props) throws BeansException {
    6. super.processProperties(beanFactoryToProcess, props);
    7. ctxPropertiesMap = new HashMap();
    8. for(Object key: props.keySet()) {
    9. String keyStr = key.toString();
    10. String valueStr = props.getProperty(keyStr);
    11. ctxPropertiesMap.put(keyStr, valueStr);
    12. }
    13. }
    14. public String getContextProperty(String key) {
    15. return ctxPropertiesMap.get(key);
    16. }

    重写processProperties方法,将properties内容存放至ctxPropertiesMap中。

    1.2 spring相关配置

    1. "customPropertyPlaceConfigurer" class="com.baggio.common.spring.ext.CustomPropertyPlaceConfigurer">
    2. "locations">
    3. classpath:test.properties
    4. 其中test.properties内容
    5. username=root
    6. password=123456789

    2、 将properties文件的路径设置成运行时拼接

    起因:公司要将tomcat jdk mysql等都做到一个安装包,实现一键安装,但又要求相关配置文件(如数据库连接的properties文件)不能放在项目中,

    以免项目升级时容易将开发环境配置覆盖生产环境配置。而配置文件必须在安装包选择的安装目录中。描述这么多,就为了说明,配置文件是动态可变的,项目启动时才能知道。

     

    2.1 修改spring相关配置,将默认locations属性修改为自定义属性,将资源文件路径改成用变量替代

    1. "customPropertyPlaceConfigurer" class="com.baggio.common.spring.ext.CustomPropertyPlaceConfigurer">
    2. "customPropertyFiles">
    3. [filepath]test.properties

    其中,customPropertyFiles为新增属性,通过setter注入,[filepath]是动态值,在加载时替换

    2.2 在类CustomPropertyPlaceConfigurer中,添加customPropertyFiles的setter注入方法。

    //根据环境变量读取资源文件(实现动态读取资源文件)

    1. public void setCustomPropertyFiles(List customPropertyFiles) {
    2. String fileSeparator = System.getProperty("file.separator");
    3. String javaHome = System.getenv("JAVA_HOME");
    4. Properties properties = new Properties();
    5. for(String customPropertyFile: customPropertyFiles) {
    6. customPropertyFile = customPropertyFile.replace("[filepath]", javaHome + fileSeparator);
    7. Properties pro = PropertyUtils.getProperties(customPropertyFile);
    8. properties.putAll(pro);
    9. }

    //关键方法,调用父类中的方法,通过这个方法将自定义在家的properties文件加入spring

    this.setProperties(properties);

    }

    读取环境变量JAVA_HOME,替换[filepath],即需要将test.properties文件存放至JAVA_HOME下(如果一键安装包,将选择的安装路径添加至环境变量,则就可以攻击环境变量找到

    相关资源文件了)。

    3、设置数据库密码成加密状态

    起因:生产环境数据库的密码需要对外保密,知道的人越少越安全,故在配置中,将数据库密码加密可以防止被开发人员获得。

    3.1 将加密的密码存放至test.properties中

    username=root

    password=4858037DC477F327BB60D4D2CD3259668EA7A2EEEF68AFF4BB2925039E8DD22CFF2D31F2578ED11B90B1324E6A8F9E112F9E4AD1B36534686D08C7177F775B03C5739B48130A37DA70AA4EFE929EBC1E768A81E31BFF2394580FAD95C9394142623F6E87589742E7822B27B9DAC78D9D9F61BC38B4A7E592DF2C5BBFE2EEBE2C

    3.2 步骤1已经得到资源文件,在此解密,并存入资源文件

    1. @Override
    2. protected void processProperties(
    3. ConfigurableListableBeanFactory beanFactoryToProcess,
    4. Properties props) throws BeansException {
    5. String password = props.getProperty("password");
    6. password = decryptByPrivateKey(password);
    7. props.put("password", password);
    8. super.processProperties(beanFactoryToProcess, props);
    9. ctxPropertiesMap = new HashMap();
    10. for(Object key: props.keySet()) {
    11. String keyStr = key.toString();
    12. String valueStr = props.getProperty(keyStr);
    13. ctxPropertiesMap.put(keyStr, valueStr);
    14. }
    15. }

    4、实现配置文件不同场景下切换

    针对步骤2中的起因,如果不将配置文件移出项目,可以用两个配置文件,或者一个配置文件中配置两套配置来解决。

    此处用两个配置文件,这样,开发阶段,开发人员将不会再操作生产配置文件

    4.1 在步骤2基础上,在JAVA_HOME目录下添加资源文件test_dev.properties

    username=root_dev

    password=4858037DC477F327BB60D4D2CD3259668EA7A2EEEF68AFF4BB2925039E8DD22CFF2D31F2578ED11B90B1324E6A8F9E112F9E4AD1B36534686D08C7177F775B03C5739B48130A37DA70AA4EFE929EBC1E768A81E31BFF2394580FAD95C9394142623F6E87589742E7822B27B9DAC78D9D9F61BC38B4A7E592DF2C5BBFE2EEBE2C

    4.2 添加环境变量devMode

    通过此变量实现生产环境和开发环境的切换,在生产环境不需配置此变量

    4.3 修改实现类

    private static final String propertiesName = "test";

    //根据环境变量读取资源文件(实现动态读取资源文件)

    1. public void setCustomPropertyFiles(List customPropertyFiles) {
    2. String fileSeparator = System.getProperty("file.separator");
    3. String javaHome = System.getenv("JAVA_HOME");
    4. String devMode = System.getenv("devMode");
    5. Properties properties = new Properties();
    6. for(String customPropertyFile: customPropertyFiles) {
    7. customPropertyFile = customPropertyFile.replace("[filepath]", javaHome + fileSeparator);
    8. if(customPropertyFile.indexOf(propertiesName) > -1) {
    9. String selectMode = devMode == null ? "":devMode;
    10. customPropertyFile = customPropertyFile.replace(propertiesName, propertiesName + selectMode);
    11. }
    12. Properties pro = PropertyUtils.getProperties(customPropertyFile);
    13. properties.putAll(pro);
    14. }

    //关键方法,调用父类中的方法,通过这个方法将自定义在家的properties文件加入spring

    this.setProperties(properties);

    }

    5、相关代码

    1. 5.1 applicationContext-propertyHolderPlaceConfigurer.xml
    2. "customPropertyPlaceConfigurer" class="com.baggio.common.spring.ext.CustomPropertyPlaceConfigurer">
    3. "customPropertyFiles">
    4. [filepath]test.properties
    5. 5.2 CustomPropertyPlaceConfigurer.java
    6. public class CustomPropertyPlaceConfigurer extends
    7. PropertyPlaceholderConfigurer {
    8. private Map ctxPropertiesMap;
    9. private static final String modulus = "92441782767737168436954696909693024093858863793961614402344444228605172372365323551758683343929072119833664753887689264694957015832845985460688129219184238713260973364694630820191644812136716548792835729282422798366717212011721279467766827116978941847031775579004384556944199142453248284103715410910396365107";
    10. private static final String privateKey = "32679115967513537671046377130533408337374645717358174504074279931768689954116908251020723800481388267273545402109800340028575676988805953753654005794437645857893594581228615872260459962755278225682193031026820777624756496861897491016205372128604377845082143258059385192300542462832051528405770845154897431553";
    11. //4858037DC477F327BB60D4D2CD3259668EA7A2EEEF68AFF4BB2925039E8DD22CFF2D31F2578ED11B90B1324E6A8F9E112F9E4AD1B36534686D08C7177F775B03C5739B48130A37DA70AA4EFE929EBC1E768A81E31BFF2394580FAD95C9394142623F6E87589742E7822B27B9DAC78D9D9F61BC38B4A7E592DF2C5BBFE2EEBE2C
    12. private static final String propertiesName = "test";

    //根据环境变量读取资源文件(实现动态读取资源文件)

    1. public void setCustomPropertyFiles(List customPropertyFiles) {
    2. String fileSeparator = System.getProperty("file.separator");
    3. String javaHome = System.getenv("JAVA_HOME");
    4. String devMode = System.getenv("devMode");
    5. Properties properties = new Properties();
    6. for(String customPropertyFile: customPropertyFiles) {
    7. customPropertyFile = customPropertyFile.replace("[filepath]", javaHome + fileSeparator);
    8. if(customPropertyFile.indexOf(propertiesName) > -1) {
    9. String selectMode = devMode == null ? "":devMode;
    10. customPropertyFile = customPropertyFile.replace(propertiesName, propertiesName + selectMode);
    11. }
    12. Properties pro = PropertyUtils.getProperties(customPropertyFile);
    13. properties.putAll(pro);
    14. }

    //关键方法,调用父类中的方法,通过这个方法将自定义在家的properties文件加入spring

    this.setProperties(properties);

    }

    @Override

    1. protected void processProperties(
    2. ConfigurableListableBeanFactory beanFactoryToProcess,
    3. Properties props) throws BeansException {
    4. String password = props.getProperty("password");
    5. password = decryptByPrivateKey(password);
    6. props.put("password", password);
    7. super.processProperties(beanFactoryToProcess, props);
    8. ctxPropertiesMap = new HashMap();
    9. for(Object key: props.keySet()) {
    10. String keyStr = key.toString();
    11. String valueStr = props.getProperty(keyStr);
    12. ctxPropertiesMap.put(keyStr, valueStr);
    13. }
    14. }
    15. public Map getCtxPropertiesMap() {
    16. return ctxPropertiesMap;
    17. }
    18. public String getContextProperty(String key) {
    19. return ctxPropertiesMap.get(key);
    20. }
    21. private String decryptByPrivateKey(String password){
    22. String mingwen = null;
    23. try {
    24. RSAPrivateKey priKey = RSAUtils
    25. .getPrivateKey(modulus, privateKey);
    26. // 解密后的明文
    27. mingwen = RSAUtils.decryptByPrivateKey(password, priKey);
    28. } catch(Exception e) {
    29. e.printStackTrace();
    30. }
    31. return mingwen;
    32. }
    33. public static void main(String[] args) {
    34. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-propertyHolderPlaceConfigurer.xml");
    35. CustomPropertyPlaceConfigurer cu = (CustomPropertyPlaceConfigurer) context.getBean("customPropertyPlaceConfigurer");
    36. Map map = cu.getCtxPropertiesMap();
    37. Iterator it = map.keySet().iterator();
    38. while(it.hasNext()) {
    39. String key = (String)it.next();
    40. String value = map.get(key);
    41. System.out.println(key + ":" + value);
    42. }
    43. }
    44. }
    45. 5.3 PropertyUtils.java
    46. public class PropertyUtils {
    47. public static Properties getProperties(String filename) {
    48. FileInputStream fis = null;
    49. Properties p = new Properties();
    50. try {
    51. fis = new FileInputStream(filename);
    52. p.load(fis);
    53. }catch (Exception e) {
    54. e.printStackTrace();
    55. }finally {
    56. if(fis != null) {
    57. try {
    58. fis.close();
    59. }catch (Exception e) {}
    60. }
    61. }
    62. return p;
    63. }
    64. }
    65. 5.4 RSAUtils.java
    66. public class RSAUtils {
    67. /**
    68. * 生成公钥和私钥
    69. *
    70. * @throws NoSuchAlgorithmException
    71. *
    72. */
    73. public static HashMap getKeys()
    74. throws NoSuchAlgorithmException {
    75. HashMap map = new HashMap();
    76. KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    77. keyPairGen.initialize(1024);
    78. KeyPair keyPair = keyPairGen.generateKeyPair();
    79. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    80. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
    81. map.put("public", publicKey);
    82. map.put("private", privateKey);
    83. return map;
    84. }
    85. /**
    86. * 使用模和指数生成RSA公钥
    87. * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
    88. * /None/NoPadding】
    89. *
    90. * @param modulus
    91. * 模
    92. * @param exponent
    93. * 指数
    94. * @return
    95. */
    96. public static RSAPublicKey getPublicKey(String modulus, String exponent) {
    97. try {
    98. BigInteger b1 = new BigInteger(modulus);
    99. BigInteger b2 = new BigInteger(exponent);
    100. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    101. RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
    102. return (RSAPublicKey) keyFactory.generatePublic(keySpec);
    103. } catch (Exception e) {
    104. e.printStackTrace();
    105. return null;
    106. }
    107. }
    108. /**
    109. * 使用模和指数生成RSA私钥
    110. * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
    111. * /None/NoPadding】
    112. *
    113. * @param modulus
    114. * 模
    115. * @param exponent
    116. * 指数
    117. * @return
    118. */
    119. public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
    120. try {
    121. BigInteger b1 = new BigInteger(modulus);
    122. BigInteger b2 = new BigInteger(exponent);
    123. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    124. RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
    125. return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    126. } catch (Exception e) {
    127. e.printStackTrace();
    128. return null;
    129. }
    130. }
    131. /**
    132. * 公钥加密
    133. *
    134. * @param data
    135. * @param publicKey
    136. * @return
    137. * @throws Exception
    138. */
    139. public static String encryptByPublicKey(String data, RSAPublicKey publicKey)
    140. throws Exception {
    141. Cipher cipher = Cipher.getInstance("RSA");
    142. cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    143. // 模长
    144. int key_len = publicKey.getModulus().bitLength() / 8;
    145. // 加密数据长度 <= 模长-11
    146. String[] datas = splitString(data, key_len - 11);
    147. String mi = "";
    148. // 如果明文长度大于模长-11则要分组加密
    149. for (String s : datas) {
    150. mi += bcd2Str(cipher.doFinal(s.getBytes()));
    151. }
    152. return mi;
    153. }
    154. /**
    155. * 私钥解密
    156. *
    157. * @param data
    158. * @param privateKey
    159. * @return
    160. * @throws Exception
    161. */
    162. public static String decryptByPrivateKey(String data,
    163. RSAPrivateKey privateKey) throws Exception {
    164. Cipher cipher = Cipher.getInstance("RSA");
    165. cipher.init(Cipher.DECRYPT_MODE, privateKey);
    166. // 模长
    167. int key_len = privateKey.getModulus().bitLength() / 8;
    168. byte[] bytes = data.getBytes();
    169. byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
    170. //System.err.println(bcd.length);
    171. // 如果密文长度大于模长则要分组解密
    172. String ming = "";
    173. byte[][] arrays = splitArray(bcd, key_len);
    174. for (byte[] arr : arrays) {
    175. ming += new String(cipher.doFinal(arr));
    176. }
    177. return ming;
    178. }
    179. /**
    180. * ASCII码转BCD码
    181. *
    182. */
    183. public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
    184. byte[] bcd = new byte[asc_len / 2];
    185. int j = 0;
    186. for (int i = 0; i < (asc_len + 1) / 2; i++) {
    187. bcd[i] = asc_to_bcd(ascii[j++]);
    188. bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
    189. }
    190. return bcd;
    191. }
    192. public static byte asc_to_bcd(byte asc) {
    193. byte bcd;
    194. if ((asc >= '0') && (asc <= '9'))
    195. bcd = (byte) (asc - '0');
    196. else if ((asc >= 'A') && (asc <= 'F'))
    197. bcd = (byte) (asc - 'A' + 10);
    198. else if ((asc >= 'a') && (asc <= 'f'))
    199. bcd = (byte) (asc - 'a' + 10);
    200. else
    201. bcd = (byte) (asc - 48);
    202. return bcd;
    203. }
    204. /**
    205. * BCD转字符串
    206. */
    207. public static String bcd2Str(byte[] bytes) {
    208. char temp[] = new char[bytes.length * 2], val;
    209. for (int i = 0; i < bytes.length; i++) {
    210. val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
    211. temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
    212. val = (char) (bytes[i] & 0x0f);
    213. temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
    214. }
    215. return new String(temp);
    216. }
    217. /**
    218. * 拆分字符串
    219. */
    220. public static String[] splitString(String string, int len) {
    221. int x = string.length() / len;
    222. int y = string.length() % len;
    223. int z = 0;
    224. if (y != 0) {
    225. z = 1;
    226. }
    227. String[] strings = new String[x + z];
    228. String str = "";
    229. for (int i = 0; i < x + z; i++) {
    230. if (i == x + z - 1 && y != 0) {
    231. str = string.substring(i * len, i * len + y);
    232. } else {
    233. str = string.substring(i * len, i * len + len);
    234. }
    235. strings[i] = str;
    236. }
    237. return strings;
    238. }
    239. /**
    240. * 拆分数组
    241. */
    242. public static byte[][] splitArray(byte[] data, int len) {
    243. int x = data.length / len;
    244. int y = data.length % len;
    245. int z = 0;
    246. if (y != 0) {
    247. z = 1;
    248. }
    249. byte[][] arrays = new byte[x + z][];
    250. byte[] arr;
    251. for (int i = 0; i < x + z; i++) {
    252. arr = new byte[len];
    253. if (i == x + z - 1 && y != 0) {
    254. System.arraycopy(data, i * len, arr, 0, y);
    255. } else {
    256. System.arraycopy(data, i * len, arr, 0, len);
    257. }
    258. arrays[i] = arr;
    259. }
    260. return arrays;
    261. }
    262. public static void main(String[] args) throws Exception {
    263. // TODO Auto-generated method stub
    264. HashMap map = RSAUtils.getKeys();
    265. // 生成公钥和私钥
    266. RSAPublicKey publicKey = (RSAPublicKey) map.get("public");
    267. RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private");
    268. // 模
    269. String modulus = publicKey.getModulus().toString();
    270. // 公钥指数
    271. String public_exponent = publicKey.getPublicExponent().toString();
    272. // 私钥指数
    273. String private_exponent = privateKey.getPrivateExponent().toString();
    274. // 明文
    275. String ming = "123456789";
    276. // 使用模和指数生成公钥和私钥
    277. RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);
    278. System.out.println("模:" + modulus);
    279. System.out.println("私钥:" + private_exponent);
    280. RSAPrivateKey priKey = RSAUtils
    281. .getPrivateKey(modulus, private_exponent);
    282. // 加密后的密文
    283. String mi = RSAUtils.encryptByPublicKey(ming, pubKey);
    284. System.out.println("加密后:" + mi);
    285. // 解密后的明文
    286. ming = RSAUtils.decryptByPrivateKey(mi, priKey);
    287. System.out.println("解密后:" + ming);
    288. }
    289. }

     

     

  • 相关阅读:
    地平线开发者社区真心话大冒险,邀你闯关!
    QT信号槽机制
    Netty(二)- NIO三大组件之Buffer
    工作【当van-tab不满足固定在顶部】
    【C++】unordered_map和unordered_set
    《新资源新蓝海-人类智能共同体》
    Dragonfly 中 P2P 传输协议优化
    自己写个网盘系列:① 来学习开启这个项目吧
    魅族MX4安装Ubuntu Touch 16.04
    face_recognition结合opencv进行多人脸识别
  • 原文地址:https://blog.csdn.net/2301_78835635/article/details/133952360