Spring series custom extension PropertyPlaceHolderConfigurer

Spring series custom extension PropertyPlaceHolderConfigurer

Table of Contents

Spring series custom extension PropertyPlaceHolderConfigurer

This article introduces the spring series’ custom extension PropertyPlaceHolderConfigurer to everyone. The main content includes its usage examples, application skills, summary of basic knowledge points and matters needing attention. It has certain reference value and friends in need can refer to it.

1. Introduction to PropertyPlaceHolderConfigurer

Mainly used to move some configuration information out of the xml file and into the properties file

2. Expand use

1. Set the properties content to be globally readable by java

Idea: When spring starts, it will load properties to its designated cache mechanism. You can use its loading mechanism to save a copy of the properties to a variable and provide an access interface to the outside world.

1.1 Create a subclass of PropertyPlaceHolderConfigurer, the code is as follows CustomPropertyPlaceConfigurer

 private Map<String, String> ctxPropertiesMap;
        @Override
        protected void processProperties(
                ConfigurableListableBeanFactory beanFactoryToProcess,
                Properties props) throws BeansException {
            super.processProperties(beanFactoryToProcess, props);
            ctxPropertiesMap = new HashMap<String, String>();
            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);
        }

Rewrite the processProperties method and store the properties content in ctxPropertiesMap.

1.2 spring related configuration

 <bean id="customPropertyPlaceConfigurer" class="com.baggio.common.spring.ext.CustomPropertyPlaceConfigurer">
           <property name="locations">
         <list>
        <value>classpath:test.properties</value>
         </list>
       </property>
    </bean>
      The content of test.properties
      username=root
      password=123456789

2. Set the path of the properties file to runtime splicing

Reason: The company wants to make tomcat, jdk, mysql, etc. into an installation package to achieve one-click installation, but it also requires that related configuration files (such as database connection properties files) cannot be placed in the project.

This prevents the development environment configuration from overwriting the production environment configuration easily when the project is upgraded. The configuration file must be in the installation directory selected by the installation package. There are so many descriptions just to illustrate that the configuration file is dynamically variable and can only be known when the project is started.

2.1 Modify the spring-related configuration, change the default locations attribute to a custom attribute, and replace the resource file path with a variable.

 <bean id="customPropertyPlaceConfigurer" class="com.baggio.common.spring.ext.CustomPropertyPlaceConfigurer">
        <property name="customPropertyFiles">
            <list>
                <value>[filepath]test.properties</value>
            </list>
        </property>
        </bean>

Among them, customPropertyFiles is a new property, injected through setter, [filepath] is a dynamic value, replaced when loading

2.2 In class CustomPropertyPlaceConfigurer, add the setter injection method of customPropertyFiles.

//Read resource files based on environment variables (to achieve dynamic reading of resource files)

 public void setCustomPropertyFiles(List<String> 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);
        }

//Key method, call the method in the parent class, and add the customized properties file to spring through this method

this.setProperties(properties);

}

Read the environment variable JAVA_HOME and replace [filepath], that is, you need to store the test.properties file under JAVA_HOME (if you install the package with one click and add the selected installation path to the environment variable, you can attack the environment variable to find it.

related resource files).

3. Set the database password to encrypted state

Reason: The password of the production environment database needs to be kept secret. The fewer people who know it, the safer it is. Therefore, in the configuration, encrypting the database password can prevent it from being obtained by developers.

3.1 Store the encrypted password in test.properties

username=root

password=4858037DC477F327BB60D4D2CD3259668EA7A2EEEF68AFF4BB2925039E8DD22CFF2D31F2578ED11B90B1324E6A8F9E112F9E4AD1B36534686D08C7177F775B03C5739B 48130A37DA70AA4EFE929EBC1E768A81E31BFF2394580FAD95C9394142623F6E87589742E7822B27B9DAC78D9D9F61BC38B4A7E592DF2C5BBFE2EEBE2C

3.2 Step 1 has obtained the resource file, decrypt it here, and store it in the resource file

 @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<String, String>();
        for(Object key: props.keySet()) {
            String keyStr = key.toString();
            String valueStr = props.getProperty(keyStr);
            ctxPropertiesMap.put(keyStr, valueStr);
        }
    }

4. Implement configuration file switching in different scenarios

For the cause in step 2, if the configuration file is not moved out of the project, it can be solved by using two configuration files, or configuring two sets of configurations in one configuration file.

Two configuration files are used here, so that during the development phase, developers will no longer operate the production configuration file.

4.1 Based on step 2, add the resource file test_dev.properties in the JAVA_HOME directory

username=root_dev

password=4858037DC477F327BB60D4D2CD3259668EA7A2EEEF68AFF4BB2925039E8DD22CFF2D31F2578ED11B90B1324E6A8F9E112F9E4AD1B36534686D08C7177F775B03C5739B 48130A37DA70AA4EFE929EBC1E768A81E31BFF2394580FAD95C9394142623F6E87589742E7822B27B9DAC78D9D9F61BC38B4A7E592DF2C5BBFE2EEBE2C

4.2 Add environment variable devMode

Use this variable to switch between the production environment and the development environment. There is no need to configure this variable in the production environment.

4.3 Modify the implementation class

private static final String propertiesName = “test”;

//Read resource files based on environment variables (to achieve dynamic reading of resource files)

 public void setCustomPropertyFiles(List<String> 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);
        }

//Key method, call the method in the parent class, and add the customized properties file to spring through this method

this.setProperties(properties);

}

5. Related codes

 5.1 applicationContext-propertyHolderPlaceConfigurer.xml
<bean id="customPropertyPlaceConfigurer" class="com.baggio.common.spring.ext.CustomPropertyPlaceConfigurer">
 <property name="customPropertyFiles">
 <list>
 <value>[filepath]test.properties</value>
 </list>
 </property>
 </bean>
5.2 CustomPropertyPlaceConfigurer.java
public class CustomPropertyPlaceConfigurer extends
 PropertyPlaceholderConfigurer {
 private Map<String, String> ctxPropertiesMap;
 private static final String modulus = "9244178276773716843695469690969302409385886379396161440234444422860517237236532355175868334392907211983366475388768 92646949570158328459854606881292191842387132609733646946308201916448121367165487928357292824227983667172120117212794677668271 16978941847031775579004384556944199142453248284103715410910396365107";
 private static final String privateKey = "32679115967513537671046377130533408337374645717358174504074279931768689954116908251020723800481388267273545402109800 34002857567698880595375365400579443764585789359458122861587226045996275527822568219303102682077762475649686189749101620537212 8604377845082143258059385192300542462832051528405770845154897431553";
 //4858037DC477F327BB60D4D2CD3259668EA7A2EEEF68AFF4BB2925039E8DD22CFF2D31F2578ED11B90B1324E6A8F9E112F9E4AD1B36534686D08C7177F775B03C5739B4 8130A37DA70AA4EFE929EBC1E768A81E31BFF2394580FAD95C9394142623F6E87589742E7822B27B9DAC78D9D9F61BC38B4A7E592DF2C5BBFE2EEBE2C
 private static final String propertiesName = "test";

//Read resource files based on environment variables (to achieve dynamic reading of resource files)

 public void setCustomPropertyFiles(List<String> 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);
 }

//Key method, call the method in the parent class, and add the customized properties file to spring through this method

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<String, String>();
 for(Object key: props.keySet()) {
 String keyStr = key.toString();
 String valueStr = props.getProperty(keyStr);
 ctxPropertiesMap.put(keyStr, valueStr);
 }
 }
 public Map<String, String> 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);
 //Decrypted plaintext
 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<String, String> map = cu.getCtxPropertiesMap();
 Iterator<String> 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 {
 /**
  * Generate public and private keys
  *
  * @throws NoSuchAlgorithmException
  *
  */
 public static HashMap<String, Object> getKeys()
 throws NoSuchAlgorithmException {
 HashMap<String, Object> map = new HashMap<String, Object>();
 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;
 }
 /**
  * Generate RSA public key using module and exponent
  * Note: [This code uses the default padding method, which is RSA/None/PKCS1Padding. The default padding method of different JDKs may be different. For example, the default padding method of Android is RSA
  * /None/NoPadding]
  *
  * @param modulus
  *Module
  * @param exponent
  * Index
  * @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;
 }
 }
 /**
  * Generate RSA private key using module and exponent
  * Note: [This code uses the default padding method, which is RSA/None/PKCS1Padding. The default padding method of different JDKs may be different. For example, the default padding method of Android is RSA
  * /None/NoPadding]
  *
  * @param modulus
  *Module
  * @param exponent
  * Index
  * @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;
 }
 }
 /**
  * Public key encryption
  *
  * @param data
  * @param publicKey
  * @return
  * @throwsException
  */
 public static String encryptByPublicKey(String data, RSAPublicKey publicKey)
 throws Exception {
 Cipher cipher = Cipher.getInstance("RSA");
 cipher.init(Cipher.ENCRYPT_MODE, publicKey);
 //Model length
 int key_len = publicKey.getModulus().bitLength() / 8;
 // Encrypted data length <= module length-11
 String[] datas = splitString(data, key_len - 11);
 String mi = "";
 // If the plaintext length is greater than the module length -11, block encryption is required
 for (String s : datas) {
 mi + = bcd2Str(cipher.doFinal(s.getBytes()));
 }
 returnmi;
 }
 /**
  * Private key decryption
  *
  * @param data
  * @param privateKey
  * @return
  * @throwsException
  */
 public static String decryptByPrivateKey(String data,
 RSAPrivateKey privateKey) throws Exception {
 Cipher cipher = Cipher.getInstance("RSA");
 cipher.init(Cipher.DECRYPT_MODE, privateKey);
 //Model length
 int key_len = privateKey.getModulus().bitLength() / 8;
 byte[] bytes = data.getBytes();
 byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
 //System.err.println(bcd.length);
 // If the ciphertext length is greater than the module length, group decryption is required
 String ming = "";
 byte[][] arrays = splitArray(bcd, key_len);
 for (byte[] arr : arrays) {
 ming + = new String(cipher.doFinal(arr));
 }
 return ming;
 }
 /**
  * Convert ASCII code to BCD code
  *
  */
 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') & amp; & amp; (asc <= '9'))
 bcd = (byte) (asc - '0');
 else if ((asc >= 'A') & amp; & amp; (asc <= 'F'))
 bcd = (byte) (asc - 'A' + 10);
 else if ((asc >= 'a') & amp; & amp; (asc <= 'f'))
 bcd = (byte) (asc - 'a' + 10);
 else
 bcd = (byte) (asc - 48);
 return bcd;
 }
 /**
  * BCD to string
  */
 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] & amp; 0xf0) >> 4) & amp; 0x0f);
 temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
 val = (char) (bytes[i] & amp; 0x0f);
 temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
 }
 return new String(temp);
 }
 /**
  * Split string
  */
 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 & amp; & y != 0) {
 str = string.substring(i * len, i * len + y);
 } else {
 str = string.substring(i * len, i * len + len);
 }
 strings[i] = str;
 }
 return strings;
 }
 /**
  * Split the array
  */
 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 & amp; & 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<String, Object> map = RSAUtils.getKeys();
 // Generate public and private keys
 RSAPublicKey publicKey = (RSAPublicKey) map.get("public");
 RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private");
 //Module
 String modulus = publicKey.getModulus().toString();
 // Public key index
 String public_exponent = publicKey.getPublicExponent().toString();
 // Private key index
 String private_exponent = privateKey.getPrivateExponent().toString();
 // plain text
 String ming = "123456789";
 // Generate public and private keys using modulus and exponent
 RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);
 System.out.println("module:" + modulus);
 System.out.println("Private key: " + private_exponent);
 RSAPrivateKey priKey = RSAUtils
 .getPrivateKey(modulus, private_exponent);
 //Encrypted ciphertext
 String mi = RSAUtils.encryptByPublicKey(ming, pubKey);
 System.out.println("After encryption: " + mi);
 //Decrypted plaintext
 ming = RSAUtils.decryptByPrivateKey(mi, priKey);
 System.out.println("After decryption: " + ming);
 }
}

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 138117 people are learning the system