進行數(shù)據(jù)源或者 ftp 服務(wù)器等資源配置時,我們可以將這些配置信息放到一個獨立的外部屬性文件中,并在 spring 配置文件中通過形如 ${user}、${password} 的占位符方式來引用屬性文件中的屬性項 。
這種方式的配置有兩個好處:
- 減少了維護的工作量 - 資源的配置信息可以被多個應(yīng)用共享,如果資源的配置信息發(fā)生了變更,那么我們只需要調(diào)整這個獨立的配置文件就可以啦。
- 部署更加簡單 - 通過一個獨立的屬性文件來存放這些配置信息,則部屬人員只需要調(diào)整這個屬性文件即可,無須關(guān)注結(jié)構(gòu)復(fù)雜、信息量大的 spring 配置文件咯。
spring 提供了一個 propertyplaceholderconfigurer ,它能夠在裝載 bean 時引用外部屬性文件 。propertyplaceholderconfigurer 實現(xiàn)了 beanfactorypostprocessorbean 接口,所以它是一個 bean 工廠后處理器。
1 基本引用
1.1 propertyplaceholderconfigurer 方式(xml 配置)
假設(shè)需要在 bean 中定義一個數(shù)據(jù)源:
1
2
3
4
5
6
|
<bean id= "datasource" class = "org.apache.commons.dbcp.basicdatasource" destroy-method= "close" p:driverclassname= "com.mysql.jdbc.driver" p:url= "jdbc:mysql://127.0.0.1:3306/spring4" p:username= "root" p:password= "" /> |
這里把驅(qū)動類名 、jdbc 的 url 以及數(shù)據(jù)庫的用戶名和密碼都直接寫在了 xml 中 。 這樣在部署時,如果需要改動數(shù)據(jù)庫的配置信息,那么首先需要先找到這個 xml,然后再進行修改,不方便 。
建議將這些信息抽取到一個配置文件中,假設(shè)取名為 system.priperties:
1
2
3
4
|
driverclassname=com.mysql.jdbc.driver url=jdbc:mysql: //127.0.0.1:3306/spring4 username=root password= |
屬性文件可以定義多個屬性,每個屬性的格式為:屬性名=屬性值
spring 配置:
1
2
3
4
5
6
7
8
9
10
11
12
|
<!-- 引入外部屬性文件--> <bean class = "org.springframework.beans.factory.config.propertyplaceholderconfigurer" p:location= "classpath:system.properties" p:fileencoding= "utf-8" /> <!-- 數(shù)據(jù)源--> <bean id= "datasource" class = "org.apache.commons.dbcp.basicdatasource" destroy-method= "close" p:driverclassname= "${driverclassname}" p:url= "${url}" p:username= "${username}" p:password= "${password}" /> |
通過這樣配置之后,我們在部署時,僅需關(guān)注這個配置文件即可。
propertyplaceholderconfigurer 屬性說明如下:
屬性 | 說明 |
---|---|
location | 指定屬性文件的路徑。 |
locations | 指定多個屬性文件的路徑。 |
fileencoding | 文件的編碼格式,如果不指定,那么 spring 會使用操作系統(tǒng)的默認編碼格式來讀取文件的內(nèi)容。 |
order | 如果配置文件中定義了多個 propertyplaceholderconfigurer ,那么可以通過這個屬性來指定優(yōu)先順序。 |
placeholderprefix | 占位符后綴,默認為 ${。 |
placeholdersuffix | 占位符前綴,默認為 }。 |
1.2 context:property-placehoder 方式(xml 配置)
可以使用 context 命名空間來定義屬性文件,相對于 propertyplaceholderconfigurer 的配置方式,這種方式更優(yōu)雅。
1
2
|
<context:property-placeholder location= "classpath:system.properties" file-encoding= "utf-8" /> |
這種方式雖然如果希望對屬性進行加密或者使用數(shù)據(jù)庫表保存配置信息等的高級功能,就必須擴展 propertyplaceholderconfigurer 的類,然后采用之前所說的 bean 配置方式 。
1.3 @value 方式(基于注解或 java 類的配置)
基于注解的 bean 可以通過 @value 注解為 bean 的成員變量或者方法入?yún)⒆詣幼⑷雽傩灾?。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@component public class customdatasource { @value ( "${driverclassname}" ) private string driverclassname; @value ( "${url}" ) private string url; @value ( "${username}" ) private string username; @value ( "${password}" ) private string password; //省略 getter/setter } |
而基于 java 類注解 @configuration 的類本身就標(biāo)注了 @component,所以它引用屬性的方式和基于注解配置的引用方式是一樣的 。
注意:使用過程中要確保所引用的屬性值在屬性文件中存在并且類型匹配,否則會拋出異常。
2 加密屬性值
對于那些不敏感的屬性信息,在屬性文件中以明文形式出現(xiàn)是合理的,但是如果屬性信息是敏感信息(比如數(shù)據(jù)庫用戶名和密碼等),建議以密文的方式保存 。 因為如果敏感信息密文保存,那么任何擁有服務(wù)器登陸權(quán)限的人就有可能看到機密信息,從而影響系統(tǒng)安全。
對于那些對安全要求特別高的系統(tǒng)(銀行、公安系統(tǒng)等),這些敏感信息應(yīng)該只掌握在少數(shù)特定的維護人員手里。所以,我們需要對這些信息進行加密,spring 容器讀取文件后,再對其進行解密。
propertyplaceholderconfigurer 繼承自 placeholderconfigurersupport 類,后者設(shè)計了一些方法,用于在屬性被使用之前對它們進行轉(zhuǎn)換:
方法 | 說明 |
---|---|
convertproperty(string propertyname, string propertyvalue) | 加載并讀取每一個屬性值時,都會調(diào)用此方法對其進行轉(zhuǎn)換處理。 |
string convertpropertyvalue(string originalvalue) | 與前一個方法功能相似,只不過參數(shù)只傳入了屬性值。 |
void convertproperties(properties props) | 轉(zhuǎn)換所有的屬性值。 |
默認情況下,這三個都是空方法,我們可以擴展 propertyplaceholderconfigurer ,覆蓋相應(yīng)的轉(zhuǎn)換方法,從而支持帶加密后的屬性值文件。
2.1 des 加密解密工具類
信息的加密分為對稱和非對稱兩種方式, 對稱表示加密后的信息可以解密出來,而非對稱方式則不能根據(jù)加密后的信息解密為原值 。 md5 屬于非對稱加密, des 屬于對稱加密 。所以這里我們使用 des 加密屬性值;讀取屬性值時,再使用 des 進行解密 。
des 加密解密工具類源代碼請點擊這里。
des 加解密使用說明:
我們使用 des 加解密工具,通過命令行的方式,對數(shù)據(jù)庫的賬號與密碼進行加密;接著,把加密后的字符串寫入 system.properties,形如:
1
2
|
username=q5l+2pprspq= password=udyjsvkxc/q= |
2.2 對屬性文件的值進行加密
首先自定義屬性配置器,支持解密轉(zhuǎn)換:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public class custompropertyplaceholderconfigurer extends propertyplaceholderconfigurer { /** * des 密鑰 */ private static final string key_str = "123456" ; /** * 值加密過的屬性名稱組 */ public static final string[] encrypt_property_names = new string[]{ "username" , "password" }; @override protected string convertproperty(string propertyname, string propertyvalue) { if (!isdecrypt(propertyname)) { return propertyvalue; } //解密 return new des(key_str).decrypt(propertyvalue); } /** * 是否需要解密 * * @param propertyname 屬性名稱 * @return */ private boolean isdecrypt(string propertyname) { return arrayutils.contains(encrypt_property_names, propertyname); } } |
注意:
- 這里的 des 密鑰必須與之前加密的密鑰相同。
- arrayutils 來源于 commons-lang3。
然后通過 <bean> 的方式來配置自定義的屬性文件:
1
2
3
|
<bean class = "net.deniro.spring4.properties.custompropertyplaceholderconfigurer" p:location= "classpath:system.properties" p:fileencoding= "utf-8" /> |
這樣,spring 容器就可以加載被加密過的屬性文件啦,是不是很簡單呀
o(∩_∩)o哈哈~
3 對自身的引用
spring 既允許在 bean 定義中通過 ${propname}引用屬性的值,也允許在屬性文件中使用 ${propname} 實現(xiàn)屬性之間的相互引用 。
1
2
3
4
|
database=spring4 driverclassname=com.mysql.jdbc.driver url=jdbc:mysql: //127.0.0.1:3306/${database} |
這里通過 ${database}引用了另外一個屬性的值(數(shù)據(jù)庫實例名)。因此,對于一些復(fù)雜的屬性,我們可以通過這種方式將屬性變化的部分抽取出來,從而實現(xiàn)配置的最小化 。
注意:如果一個屬性值太長,我們可以在每一行的最后加上 “\”,就可以把屬性值劃分為多行,就像這樣:
1
2
3
|
profile.jdbc.url=jdbc:mysql: //127.0.0.1:3306/dbname?useunicode=true&characterencoding\ =utf- 8 \ &zerodatetimebehavior=converttonull |
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://www.jianshu.com/p/cc61f687f171