In our development, we often use the spring framework to read property values for property files, and then use placeholders to reference property values of property files to simplify configuration and make configurations more flexible and versatile.
such as the following property profile: Db.properties
#数据库配置
Db.driver=org.postgresql.driver
Db.url=jdbc\:p Ostgresql\://10.166.176.127\:5432/test
Db.username=ivsadmin
db.password=123456
Db.name=ivs
Applicationcontext.xml file
<context:property-placeholder location= "classpath:db.properties"/> <bean id= "DataSource
"
class= "Com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method= "Close" >
<property name= "Driverclass" Value= "${db.driver}"/> <property name= "Jdbcurl" value= "
${db.url}"/> <property name=
"User" Value= "${db.username}"/> <property name= "password" value=
"${db.password}"/> <property name=
" Checkouttimeout "value=" 3000 "/>
</bean>
For some sensitive property values, such as password properties. For security purposes, we typically encrypt passwords.
You might want the user to see db.properties like this:
#数据库配置
Db.driver=org.postgresql.driver
Db.url=jdbc\:p Ostgresql\://10.166.176.127\:5432/ivs
Db.username=ivsadmin
db.password={smc}synzvkgihoprkdghcyt81w==
Db.name=ivs
Here you can see that the value of the password attribute is encrypted, and the other property values are unchanged, thus achieving security purposes. Here is the use of Java 3DES encryption, in the previous article 3DES encryption, decryption tool class has been introduced
Below we start to analyze our requirements:
The configuration of external application parameters in spring is propertyplaceholderconfigurer and Propertyoverrideconfigurer objects, Propertyplaceholderconfigurer implements the Beanfactorypostprocessor interface, it can manage the attribute value in the <bean/> externally.
Just like this:
<bean id= "PropertyConfigurer1" class= "Org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
<property name= "Locations" >
<value>WEB-INF/classes/db.properties</value>
</property>
</bean>
To simplify the use of Propertyplaceholderconfigurer, Spring provides <context:property-placeholder/> elements, Like the Applicationcontext.xml file: <context:property-placeholder location= "Classpath:db.properties"/>
It is clear here that we simply inherit the Propertyplaceholderconfigurer object and rewrite the Loadproperties method of the Propertiesloadersupport interface, You can perform related operations on the property values of the subordinate files.
Understand the need to get down to start our implementation code:
Decryptpropertyplaceholderconfigurer.java
Import Java.io.File;
Import Java.io.FileOutputStream;
Import java.io.IOException;
Import Java.io.InputStream;
Import Java.io.InputStreamReader;
Import java.util.Properties;
Import Org.apache.commons.lang.StringUtils;
Import Org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
Import Org.springframework.core.io.Resource;
Import com.huawei.smc.commons.constants.CommonContants; /** * < A statement function brief > * * @author hKF44803 * @version [version number, 2011-12-6] * @see [Related class/method] * @since [Product/Module version]/p
Ublic class Decryptpropertyplaceholderconfigurer extends Propertyplaceholderconfigurer {private resource[] locations;
Private Decryptpropertiespersister Propertiespersister = new Decryptpropertiespersister ();
Private String fileencoding = "Utf-8";
Private Boolean ignoreresourcenotfound = false; /** * {@inheritDoc} */@Override public void Setlocations (resource[] locations) {This.locat ions = Locations;
}/** * {@inheritDoc} */@Override public void setfileencoding (String encoding) {
this.fileencoding = encoding; }/** * {@inheritDoc} */@Override public void Setignoreresourcenotfound (Boolean IGNORERESOURC
Enotfound) {this.ignoreresourcenotfound = Ignoreresourcenotfound; }/** * {@inheritDoc} */@Override public void loadproperties (Properties props) throws
IOException {//property file is an empty if (this.locations!= null) {//Loop Read Property file for (int i = 0; i < this.locations.length i++) {Resource location = This.locatio
Ns[i];
InputStream is = null;
FileOutputStream fos = null;
try {is = Location.getinputstream ();Check if the file is an XML file if (Location.getfilename (). EndsWith (xml_file_extension)) {
THIS.PROPERTIESPERSISTER.LOADFROMXML (props, is); }//Property file else {This.propertiespersist
Er.doload (Props, New InputStreamReader (IS, this.fileencoding));
String content = This.propertiesPersister.getEncryptContent ();
Find if there is a cryptographic ID if (stringutils.contains (content, Commoncontants.decrypt_flag)) {try {File file = location.g
Etfile ();
FOS = new FileOutputStream (file); Fos.write (This.propertiesPersister.getEncryptContENT (). GetBytes ());
Fos.flush ();
finally {if (null!= FOS)
{Fos.close (); catch (I
Oexception ex) {if (This.ignoreresourcenotfound) { if (logger.iswarnenabled ()) {Logger.warn ("could not load PR
Operties from "+ Location +": "+ ex.getmessage ());
} else {throw ex;
}} finally {
if (is!= null) {is.close (); }
}
}
}
}
}
Where the Propertiespersister variable is implemented with the Defaultpropertiespersister class we write, Decryptpropertiespersister.java object
Import Java.io.BufferedReader;
Import java.io.IOException;
Import Java.io.Reader;
Import java.util.Properties;
Import Org.springframework.util.DefaultPropertiesPersister;
Import Org.springframework.util.StringUtils;
Import com.huawei.smc.commons.constants.CommonContants;
Import com.huawei.smc.commons.constants.NumberConstants;
Import Com.huawei.smc.commons.util.ThreeDesUtil; /** * Heavy Duty Defaultpropertiespersister class * * @author hKF44803 * @version [version number, 2011-12-6] * @see [related classes/methods] * @since [ Product/Module Version] */public class Decryptpropertiespersister extends Defaultpropertiespersister {//encrypted string private Strin
G Encryptcontent;
Public String getencryptcontent () {return encryptcontent;
}/** * {@inheritDoc} * * @Override protected void doload (Properties props, reader reader)
Throws IOException {BufferedReader in = new BufferedReader (reader); The last written content StringBuilder sbcontent = New StringBuilder ();
Loop read file while (true) {//read each line String = In.readline ();
Non-null check if (line = = null) {break;
//Remove Space line = Stringutils.trimleadingwhitespace (line); Read behavior empty, jump out of Loop if (line.length () = = 0) {//length 0, line wrap Sbcontent.appe
nd ("\ n");
Continue
}//The first character char Firstchar = Line.charat (0) per line;
The first character is not # and!
if (Firstchar!= ' # ' && firstchar!= '! ') {while (endswithcontinuationmarker) {String nextline = In.read
Line ();
line = line.substring (0, Line.length ()-1); Non-null check if (nextline!= null) {line + = Stringutils.triml
Eadingwhitespace (nextline); }//Find index int separatorindex = line.indexof ("=") for all positions of equal sign
); No equal sign if (Separatorindex = 1) {Separatorindex = Line.indexof (":")
; //Fetch key String key = (Separatorindex!=-1)?
Line.substring (0, Separatorindex): line; The value of the key is String value = (separatorindex!=-1)?
Line.substring (Separatorindex + 1): "";
Remove the Space key = Stringutils.trimtrailingwhitespace (key);
Value = Stringutils.trimleadingwhitespace (value); Put all of the properties into a persistent property set * Props.put (Unescape (Key), unescape (value)); DB Property File if (CommonContants.DB_PASSWORD_PROPS.equals (key)) {//Instance encryption worker
With class Threedesutil desutil = new Threedesutil ();
DB Password decryption if (Value.startswith (Commoncontants.decrypt_flag)) {
Remove the identity value = value.substring (numberconstants.int_5);
3DES decryption of the encrypted property value = Desutil.decrypt (value);
The decrypted value is placed in the props Props.put (unescape (key), unescape (value));
}//DB password encryption else {//encrypt specified value
String Strencrypt = desutil.encrypt (value); // The encrypted value adds an identifier, distinguishing decryption, encrypting value = Commoncontants.decrypt_flag + strencrypt;
The Encrypted line = key + commoncontants.properties_seperate + value;
Sbcontent.append (line + "\ n"); }//Append additional properties else {Sbcontent.append
(line + "\ n");
} else {//append-read annotation content sbcontent.append (line + \ n);
} encryptcontent = Sbcontent.tostring (); }
}
Finally, the following applicationcontext.xml file needs to be modified, as follows:
<bean id= "PropertyConfigurer1" class= "Com.huawei.smc.commons.DecryptPropertyPlaceholderConfigurer" >
<property name= "Locations" >
<value>WEB-INF/classes/db.properties</value>
</ property>
</bean>
<bean id= "DataSource" class= "Com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method= "Close" >
<property name= "Driverclass" value= "${db.driver}"/> <property name=
" Jdbcurl "value=" ${db.url} "/>
<property name=" user "value=" ${db.username} "/> <property name=
" Password "value=" ${db.password} "/>
<property name=" checkouttimeout "value=" 3000 "/>
</bean >
This completes the encryption of the property, and the property is encrypted when spring is finished loading
Tip: If there are multiple profiles in the configuration that need to be loaded, and the property files do not require any processing, add the following configuration:
<bean id= "Propertyconfigurer"
class= " Org.springframework.beans.factory.config.PropertyPlaceholderConfigurer ">
<property name=" Order "value= "1"/>
<property name= "Ignoreunresolvableplaceholders" value= "true"/> <property "name=
" Locations ">
<value>WEB-INF/classes/smc.properties</value>
</property>