目录
spring系列之自定义扩展PropertyPlaceHolderConfigurer
本文章向大家介绍spring系列之自定义扩展PropertyPlaceHolderConfigurer,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一、PropertyPlaceHolderConfigurer介绍
主要用于将一些配置信息移出xml文件,移到至properties文件
二、拓展使用
1、将porperties内容设置成java全局可读
思路:spring启动的时候会将properties加载至其指定缓存机制,可利用其加载机制,在读取properties时,保存一份至变量,对外提供访问接口。
1.1 创建PropertyPlaceHolderConfigurer的子类,代码如下CustomPropertyPlaceConfigurer
- private Map
ctxPropertiesMap; - @Override
- protected void processProperties(
- ConfigurableListableBeanFactory beanFactoryToProcess,
- Properties props) throws BeansException {
- super.processProperties(beanFactoryToProcess, props);
- ctxPropertiesMap = new HashMap
(); - for(Object key: props.keySet()) {
- String keyStr = key.toString();
- String valueStr = props.getProperty(keyStr);
- ctxPropertiesMap.put(keyStr, valueStr);
- }
- }
- public String getContextProperty(String key) {
- return ctxPropertiesMap.get(key);
- }
重写processProperties方法,将properties内容存放至ctxPropertiesMap中。
1.2 spring相关配置
-
"customPropertyPlaceConfigurer" class="com.baggio.common.spring.ext.CustomPropertyPlaceConfigurer"> -
"locations"> -
-
classpath:test.properties -
-
-
- 其中test.properties内容
- username=root
- password=123456789
2、 将properties文件的路径设置成运行时拼接
起因:公司要将tomcat jdk mysql等都做到一个安装包,实现一键安装,但又要求相关配置文件(如数据库连接的properties文件)不能放在项目中,
以免项目升级时容易将开发环境配置覆盖生产环境配置。而配置文件必须在安装包选择的安装目录中。描述这么多,就为了说明,配置文件是动态可变的,项目启动时才能知道。
2.1 修改spring相关配置,将默认locations属性修改为自定义属性,将资源文件路径改成用变量替代
-
"customPropertyPlaceConfigurer" class="com.baggio.common.spring.ext.CustomPropertyPlaceConfigurer"> -
"customPropertyFiles"> -
-
[filepath]test.properties -
-
-
其中,customPropertyFiles为新增属性,通过setter注入,[filepath]是动态值,在加载时替换
2.2 在类CustomPropertyPlaceConfigurer中,添加customPropertyFiles的setter注入方法。
//根据环境变量读取资源文件(实现动态读取资源文件)
- public void setCustomPropertyFiles(List
customPropertyFiles) { - String fileSeparator = System.getProperty("file.separator");
- String javaHome = System.getenv("JAVA_HOME");
- Properties properties = new Properties();
- for(String customPropertyFile: customPropertyFiles) {
- customPropertyFile = customPropertyFile.replace("[filepath]", javaHome + fileSeparator);
- Properties pro = PropertyUtils.getProperties(customPropertyFile);
- properties.putAll(pro);
- }
//关键方法,调用父类中的方法,通过这个方法将自定义在家的properties文件加入spring
this.setProperties(properties);
}
读取环境变量JAVA_HOME,替换[filepath],即需要将test.properties文件存放至JAVA_HOME下(如果一键安装包,将选择的安装路径添加至环境变量,则就可以攻击环境变量找到
相关资源文件了)。
3、设置数据库密码成加密状态
起因:生产环境数据库的密码需要对外保密,知道的人越少越安全,故在配置中,将数据库密码加密可以防止被开发人员获得。
3.1 将加密的密码存放至test.properties中
username=root
password=4858037DC477F327BB60D4D2CD3259668EA7A2EEEF68AFF4BB2925039E8DD22CFF2D31F2578ED11B90B1324E6A8F9E112F9E4AD1B36534686D08C7177F775B03C5739B48130A37DA70AA4EFE929EBC1E768A81E31BFF2394580FAD95C9394142623F6E87589742E7822B27B9DAC78D9D9F61BC38B4A7E592DF2C5BBFE2EEBE2C
3.2 步骤1已经得到资源文件,在此解密,并存入资源文件
- @Override
- protected void processProperties(
- ConfigurableListableBeanFactory beanFactoryToProcess,
- Properties props) throws BeansException {
- String password = props.getProperty("password");
- password = decryptByPrivateKey(password);
- props.put("password", password);
- super.processProperties(beanFactoryToProcess, props);
- ctxPropertiesMap = new HashMap
(); - for(Object key: props.keySet()) {
- String keyStr = key.toString();
- String valueStr = props.getProperty(keyStr);
- ctxPropertiesMap.put(keyStr, valueStr);
- }
- }
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";
//根据环境变量读取资源文件(实现动态读取资源文件)
- public void setCustomPropertyFiles(List
customPropertyFiles) { - String fileSeparator = System.getProperty("file.separator");
- String javaHome = System.getenv("JAVA_HOME");
- String devMode = System.getenv("devMode");
- Properties properties = new Properties();
- for(String customPropertyFile: customPropertyFiles) {
- customPropertyFile = customPropertyFile.replace("[filepath]", javaHome + fileSeparator);
- if(customPropertyFile.indexOf(propertiesName) > -1) {
- String selectMode = devMode == null ? "":devMode;
- customPropertyFile = customPropertyFile.replace(propertiesName, propertiesName + selectMode);
- }
- Properties pro = PropertyUtils.getProperties(customPropertyFile);
- properties.putAll(pro);
- }
//关键方法,调用父类中的方法,通过这个方法将自定义在家的properties文件加入spring
this.setProperties(properties);
}
5、相关代码
- 5.1 applicationContext-propertyHolderPlaceConfigurer.xml
"customPropertyPlaceConfigurer" class="com.baggio.common.spring.ext.CustomPropertyPlaceConfigurer"> -
"customPropertyFiles"> -
-
[filepath]test.properties -
-
-
- 5.2 CustomPropertyPlaceConfigurer.java
- public class CustomPropertyPlaceConfigurer extends
- PropertyPlaceholderConfigurer {
- private Map
ctxPropertiesMap; - private static final String modulus = "92441782767737168436954696909693024093858863793961614402344444228605172372365323551758683343929072119833664753887689264694957015832845985460688129219184238713260973364694630820191644812136716548792835729282422798366717212011721279467766827116978941847031775579004384556944199142453248284103715410910396365107";
- private static final String privateKey = "32679115967513537671046377130533408337374645717358174504074279931768689954116908251020723800481388267273545402109800340028575676988805953753654005794437645857893594581228615872260459962755278225682193031026820777624756496861897491016205372128604377845082143258059385192300542462832051528405770845154897431553";
- //4858037DC477F327BB60D4D2CD3259668EA7A2EEEF68AFF4BB2925039E8DD22CFF2D31F2578ED11B90B1324E6A8F9E112F9E4AD1B36534686D08C7177F775B03C5739B48130A37DA70AA4EFE929EBC1E768A81E31BFF2394580FAD95C9394142623F6E87589742E7822B27B9DAC78D9D9F61BC38B4A7E592DF2C5BBFE2EEBE2C
- private static final String propertiesName = "test";
//根据环境变量读取资源文件(实现动态读取资源文件)
- public void setCustomPropertyFiles(List
customPropertyFiles) { - String fileSeparator = System.getProperty("file.separator");
- String javaHome = System.getenv("JAVA_HOME");
- String devMode = System.getenv("devMode");
- Properties properties = new Properties();
- for(String customPropertyFile: customPropertyFiles) {
- customPropertyFile = customPropertyFile.replace("[filepath]", javaHome + fileSeparator);
- if(customPropertyFile.indexOf(propertiesName) > -1) {
- String selectMode = devMode == null ? "":devMode;
- customPropertyFile = customPropertyFile.replace(propertiesName, propertiesName + selectMode);
- }
- Properties pro = PropertyUtils.getProperties(customPropertyFile);
- properties.putAll(pro);
- }
//关键方法,调用父类中的方法,通过这个方法将自定义在家的properties文件加入spring
this.setProperties(properties);
}
@Override
- protected void processProperties(
- ConfigurableListableBeanFactory beanFactoryToProcess,
- Properties props) throws BeansException {
- String password = props.getProperty("password");
- password = decryptByPrivateKey(password);
- props.put("password", password);
- super.processProperties(beanFactoryToProcess, props);
- ctxPropertiesMap = new HashMap
(); - for(Object key: props.keySet()) {
- String keyStr = key.toString();
- String valueStr = props.getProperty(keyStr);
- ctxPropertiesMap.put(keyStr, valueStr);
- }
- }
- public Map
getCtxPropertiesMap() { - return ctxPropertiesMap;
- }
- public String getContextProperty(String key) {
- return ctxPropertiesMap.get(key);
- }
- private String decryptByPrivateKey(String password){
- String mingwen = null;
- try {
- RSAPrivateKey priKey = RSAUtils
- .getPrivateKey(modulus, privateKey);
- // 解密后的明文
- mingwen = RSAUtils.decryptByPrivateKey(password, priKey);
- } catch(Exception e) {
- e.printStackTrace();
- }
- return mingwen;
- }
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-propertyHolderPlaceConfigurer.xml");
- CustomPropertyPlaceConfigurer cu = (CustomPropertyPlaceConfigurer) context.getBean("customPropertyPlaceConfigurer");
- Map
map = cu.getCtxPropertiesMap(); - Iterator
it = map.keySet().iterator(); - while(it.hasNext()) {
- String key = (String)it.next();
- String value = map.get(key);
- System.out.println(key + ":" + value);
- }
- }
- }
- 5.3 PropertyUtils.java
-
- public class PropertyUtils {
- public static Properties getProperties(String filename) {
- FileInputStream fis = null;
- Properties p = new Properties();
- try {
- fis = new FileInputStream(filename);
- p.load(fis);
- }catch (Exception e) {
- e.printStackTrace();
- }finally {
- if(fis != null) {
- try {
- fis.close();
- }catch (Exception e) {}
- }
- }
- return p;
- }
- }
- 5.4 RSAUtils.java
- public class RSAUtils {
- /**
- * 生成公钥和私钥
- *
- * @throws NoSuchAlgorithmException
- *
- */
- public static HashMap
getKeys() - throws NoSuchAlgorithmException {
- HashMap
map = new HashMap(); - KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
- keyPairGen.initialize(1024);
- KeyPair keyPair = keyPairGen.generateKeyPair();
- RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
- RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
- map.put("public", publicKey);
- map.put("private", privateKey);
- return map;
- }
- /**
- * 使用模和指数生成RSA公钥
- * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
- * /None/NoPadding】
- *
- * @param modulus
- * 模
- * @param exponent
- * 指数
- * @return
- */
- public static RSAPublicKey getPublicKey(String modulus, String exponent) {
- try {
- BigInteger b1 = new BigInteger(modulus);
- BigInteger b2 = new BigInteger(exponent);
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
- return (RSAPublicKey) keyFactory.generatePublic(keySpec);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- /**
- * 使用模和指数生成RSA私钥
- * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
- * /None/NoPadding】
- *
- * @param modulus
- * 模
- * @param exponent
- * 指数
- * @return
- */
- public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
- try {
- BigInteger b1 = new BigInteger(modulus);
- BigInteger b2 = new BigInteger(exponent);
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
- return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- /**
- * 公钥加密
- *
- * @param data
- * @param publicKey
- * @return
- * @throws Exception
- */
- public static String encryptByPublicKey(String data, RSAPublicKey publicKey)
- throws Exception {
- Cipher cipher = Cipher.getInstance("RSA");
- cipher.init(Cipher.ENCRYPT_MODE, publicKey);
- // 模长
- int key_len = publicKey.getModulus().bitLength() / 8;
- // 加密数据长度 <= 模长-11
- String[] datas = splitString(data, key_len - 11);
- String mi = "";
- // 如果明文长度大于模长-11则要分组加密
- for (String s : datas) {
- mi += bcd2Str(cipher.doFinal(s.getBytes()));
- }
- return mi;
- }
- /**
- * 私钥解密
- *
- * @param data
- * @param privateKey
- * @return
- * @throws Exception
- */
- public static String decryptByPrivateKey(String data,
- RSAPrivateKey privateKey) throws Exception {
- Cipher cipher = Cipher.getInstance("RSA");
- cipher.init(Cipher.DECRYPT_MODE, privateKey);
- // 模长
- int key_len = privateKey.getModulus().bitLength() / 8;
- byte[] bytes = data.getBytes();
- byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
- //System.err.println(bcd.length);
- // 如果密文长度大于模长则要分组解密
- String ming = "";
- byte[][] arrays = splitArray(bcd, key_len);
- for (byte[] arr : arrays) {
- ming += new String(cipher.doFinal(arr));
- }
- return ming;
- }
- /**
- * ASCII码转BCD码
- *
- */
- public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
- byte[] bcd = new byte[asc_len / 2];
- int j = 0;
- for (int i = 0; i < (asc_len + 1) / 2; i++) {
- bcd[i] = asc_to_bcd(ascii[j++]);
- bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
- }
- return bcd;
- }
- public static byte asc_to_bcd(byte asc) {
- byte bcd;
- if ((asc >= '0') && (asc <= '9'))
- bcd = (byte) (asc - '0');
- else if ((asc >= 'A') && (asc <= 'F'))
- bcd = (byte) (asc - 'A' + 10);
- else if ((asc >= 'a') && (asc <= 'f'))
- bcd = (byte) (asc - 'a' + 10);
- else
- bcd = (byte) (asc - 48);
- return bcd;
- }
- /**
- * BCD转字符串
- */
- public static String bcd2Str(byte[] bytes) {
- char temp[] = new char[bytes.length * 2], val;
- for (int i = 0; i < bytes.length; i++) {
- val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
- temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
- val = (char) (bytes[i] & 0x0f);
- temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
- }
- return new String(temp);
- }
- /**
- * 拆分字符串
- */
- public static String[] splitString(String string, int len) {
- int x = string.length() / len;
- int y = string.length() % len;
- int z = 0;
- if (y != 0) {
- z = 1;
- }
- String[] strings = new String[x + z];
- String str = "";
- for (int i = 0; i < x + z; i++) {
- if (i == x + z - 1 && y != 0) {
- str = string.substring(i * len, i * len + y);
- } else {
- str = string.substring(i * len, i * len + len);
- }
- strings[i] = str;
- }
- return strings;
- }
- /**
- * 拆分数组
- */
- public static byte[][] splitArray(byte[] data, int len) {
- int x = data.length / len;
- int y = data.length % len;
- int z = 0;
- if (y != 0) {
- z = 1;
- }
- byte[][] arrays = new byte[x + z][];
- byte[] arr;
- for (int i = 0; i < x + z; i++) {
- arr = new byte[len];
- if (i == x + z - 1 && y != 0) {
- System.arraycopy(data, i * len, arr, 0, y);
- } else {
- System.arraycopy(data, i * len, arr, 0, len);
- }
- arrays[i] = arr;
- }
- return arrays;
- }
- public static void main(String[] args) throws Exception {
- // TODO Auto-generated method stub
- HashMap
map = RSAUtils.getKeys(); - // 生成公钥和私钥
- RSAPublicKey publicKey = (RSAPublicKey) map.get("public");
- RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private");
- // 模
- String modulus = publicKey.getModulus().toString();
- // 公钥指数
- String public_exponent = publicKey.getPublicExponent().toString();
- // 私钥指数
- String private_exponent = privateKey.getPrivateExponent().toString();
- // 明文
- String ming = "123456789";
- // 使用模和指数生成公钥和私钥
- RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);
- System.out.println("模:" + modulus);
- System.out.println("私钥:" + private_exponent);
- RSAPrivateKey priKey = RSAUtils
- .getPrivateKey(modulus, private_exponent);
- // 加密后的密文
- String mi = RSAUtils.encryptByPublicKey(ming, pubKey);
- System.out.println("加密后:" + mi);
- // 解密后的明文
- ming = RSAUtils.decryptByPrivateKey(mi, priKey);
- System.out.println("解密后:" + ming);
- }
- }