進行數據源或者FTP 服務器等資源配置時,我們可以將這些配置信息放到一個獨立的外部屬性文件中,並在Spring 配置文件中通過形如${user}、${password} 的佔位符方式來引用屬性文件中的屬性項。
這種方式的配置有兩個好處:
Spring 提供了一個PropertyPlaceholderConfigurer ,它能夠在裝載Bean 時引用外部屬性文件。 PropertyPlaceholderConfigurer 實現了BeanFactoryPostProcessorBean 接口,所以它是一個Bean 工廠後處理器。
1 基本引用
1.1 PropertyPlaceholderConfigurer 方式(XML 配置)
假設需要在Bean 中定義一個數據源:
<bean id="dataSource" destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://127.0.0.1:3306/spring4" p:username="root" p:password=""/>
這裡把驅動類名、JDBC 的URL 以及數據庫的用戶名和密碼都直接寫在了XML 中。 這樣在部署時,如果需要改動數據庫的配置信息,那麼首先需要先找到這個XML,然後再進行修改,不方便。
建議將這些信息抽取到一個配置文件中,假設取名為system.priperties:
driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306/spring4username=rootpassword=
屬性文件可以定義多個屬性,每個屬性的格式為:属性名=属性值
spring 配置:
<!-- 引入外部屬性文件--><bean p:location="classpath:system.properties" p:fileEncoding="utf-8"/><!-- 數據源--><bean id="dataSource" destroy-method="close" p:driverClassName="${driverClassName}" p:url="${url}" p:username="${username}" p:password="${password}"/>通過這樣配置之後,我們在部署時,僅需關注這個配置文件即可。
PropertyPlaceholderConfigurer 屬性說明如下:
| 屬性 | 說明 |
|---|---|
| location | 指定屬性文件的路徑。 |
| locations | 指定多個屬性文件的路徑。 |
| fileEncoding | 文件的編碼格式,如果不指定,那麼Spring 會使用操作系統的默認編碼格式來讀取文件的內容。 |
| order | 如果配置文件中定義了多個PropertyPlaceholderConfigurer ,那麼可以通過這個屬性來指定優先順序。 |
| placeholderPrefix | 佔位符後綴,默認為${。 |
| placeholderSuffix | 佔位符前綴,默認為}。 |
1.2 context:property-placehoder 方式(XML 配置)
可以使用context 命名空間來定義屬性文件,相對於PropertyPlaceholderConfigurer 的配置方式,這種方式更優雅。
<context:property-placeholder location="classpath:system.properties" file-encoding="utf-8"/>
這種方式雖然如果希望對屬性進行加密或者使用數據庫表保存配置信息等的高級功能,就必須擴展PropertyPlaceholderConfigurer 的類,然後採用之前所說的Bean 配置方式。
1.3 @value 方式(基於註解或JAVA 類的配置)
基於註解的Bean 可以通過@Value 註解為Bean 的成員變量或者方法入參自動注入屬性值。
@Componentpublic 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 的類本身就標註了@Component,所以它引用屬性的方式和基於註解配置的引用方式是一樣的。
注意:使用過程中要確保所引用的屬性值在屬性文件中存在並且類型匹配,否則會拋出異常。
2 加密屬性值
對於那些不敏感的屬性信息,在屬性文件中以明文形式出現是合理的,但是如果屬性信息是敏感信息(比如數據庫用戶名和密碼等),建議以密文的方式保存。 因為如果敏感信息密文保存,那麼任何擁有服務器登陸權限的人就有可能看到機密信息,從而影響系統安全。
對於那些對安全要求特別高的系統(銀行、公安系統等),這些敏感信息應該只掌握在少數特定的維護人員手裡。所以,我們需要對這些信息進行加密,Spring 容器讀取文件後,再對其進行解密。
PropertyPlaceholderConfigurer 繼承自PlaceholderConfigurerSupport 類,後者設計了一些方法,用於在屬性被使用之前對它們進行轉換:
| 方法 | 說明 |
|---|---|
| convertProperty(String propertyName, String propertyValue) | 加載並讀取每一個屬性值時,都會調用此方法對其進行轉換處理。 |
| String convertPropertyValue(String originalValue) | 與前一個方法功能相似,只不過參數只傳入了屬性值。 |
| void convertProperties(Properties props) | 轉換所有的屬性值。 |
默認情況下,這三個都是空方法,我們可以擴展PropertyPlaceholderConfigurer ,覆蓋相應的轉換方法,從而支持帶加密後的屬性值文件。
2.1 DES 加密解密工具類
信息的加密分為對稱和非對稱兩種方式, 對稱表示加密後的信息可以解密出來,而非對稱方式則不能根據加密後的信息解密為原值。 MD5 屬於非對稱加密, DES 屬於對稱加密。所以這裡我們使用DES 加密屬性值;讀取屬性值時,再使用DES 進行解密。
DES 加密解密工具類源代碼請點擊這裡。
DES 加解密使用說明:
我們使用DES 加解密工具,通過命令行的方式,對數據庫的賬號與密碼進行加密;接著,把加密後的字符串寫入system.properties,形如:
username=q5L+2PPrsPQ=password=UdyjsvkXc/Q=
2.2 對屬性文件的值進行加密
首先自定義屬性配置器,支持解密轉換:
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); }}注意:
然後通過<bean> 的方式來配置自定義的屬性文件:
<bean p:location="classpath:system.properties" p:fileEncoding="utf-8"/>
這樣,Spring 容器就可以加載被加密過的屬性文件啦,是不是很簡單呀
O(∩_∩)O哈哈~
3 對自身的引用
Spring 既允許在Bean 定義中通過${propName}引用屬性的值,也允許在屬性文件中使用${propName} 實現屬性之間的相互引用。
database=spring4driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306/${database}這里通過${database}引用了另外一個屬性的值(數據庫實例名)。因此,對於一些複雜的屬性,我們可以通過這種方式將屬性變化的部分抽取出來,從而實現配置的最小化。
注意:如果一個屬性值太長,我們可以在每一行的最後加上“/”,就可以把屬性值劃分為多行,就像這樣:
profile.jdbc.url=jdbc:mysql://127.0.0.1:3306/dbName?useUnicode=true&characterEncoding/ =UTF-8/ &zeroDateTimeBehavior=convertToNull
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。