說(shuō)說(shuō)在Spring中如何引用外部屬性文件的方法
進(jìn)行數(shù)據(jù)源或者 FTP 服務(wù)器等資源配置時(shí),我們可以將這些配置信息放到一個(gè)獨(dú)立的外部屬性文件中,并在 Spring 配置文件中通過(guò)形如 ${user}、${password} 的占位符方式來(lái)引用屬性文件中的屬性項(xiàng) 。
這種方式的配置有兩個(gè)好處:
- 減少了維護(hù)的工作量 - 資源的配置信息可以被多個(gè)應(yīng)用共享,如果資源的配置信息發(fā)生了變更,那么我們只需要調(diào)整這個(gè)獨(dú)立的配置文件就可以啦。
- 部署更加簡(jiǎn)單 - 通過(guò)一個(gè)獨(dú)立的屬性文件來(lái)存放這些配置信息,則部屬人員只需要調(diào)整這個(gè)屬性文件即可,無(wú)須關(guān)注結(jié)構(gòu)復(fù)雜、信息量大的 Spring 配置文件咯。
Spring 提供了一個(gè) PropertyPlaceholderConfigurer ,它能夠在裝載 Bean 時(shí)引用外部屬性文件 。PropertyPlaceholderConfigurer 實(shí)現(xiàn)了 BeanFactoryPostProcessorBean 接口,所以它是一個(gè) Bean 工廠后處理器。
1 基本引用
1.1 PropertyPlaceholderConfigurer 方式(XML 配置)
假設(shè)需要在 Bean 中定義一個(gè)數(shù)據(jù)源:
<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ū)動(dòng)類(lèi)名 、JDBC 的 URL 以及數(shù)據(jù)庫(kù)的用戶(hù)名和密碼都直接寫(xiě)在了 XML 中 。 這樣在部署時(shí),如果需要改動(dòng)數(shù)據(jù)庫(kù)的配置信息,那么首先需要先找到這個(gè) XML,然后再進(jìn)行修改,不方便 。
建議將這些信息抽取到一個(gè)配置文件中,假設(shè)取名為 system.priperties:
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/spring4 username=root password=
屬性文件可以定義多個(gè)屬性,每個(gè)屬性的格式為:屬性名=屬性值
spring 配置:
<!-- 引入外部屬性文件--> <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ò)這樣配置之后,我們?cè)诓渴饡r(shí),僅需關(guān)注這個(gè)配置文件即可。
PropertyPlaceholderConfigurer 屬性說(shuō)明如下:
屬性 | 說(shuō)明 |
---|---|
location | 指定屬性文件的路徑。 |
locations | 指定多個(gè)屬性文件的路徑。 |
fileEncoding | 文件的編碼格式,如果不指定,那么 Spring 會(huì)使用操作系統(tǒng)的默認(rèn)編碼格式來(lái)讀取文件的內(nèi)容。 |
order | 如果配置文件中定義了多個(gè) PropertyPlaceholderConfigurer ,那么可以通過(guò)這個(gè)屬性來(lái)指定優(yōu)先順序。 |
placeholderPrefix | 占位符后綴,默認(rèn)為 ${。 |
placeholderSuffix | 占位符前綴,默認(rèn)為 }。 |
1.2 context:property-placehoder 方式(XML 配置)
可以使用 context 命名空間來(lái)定義屬性文件,相對(duì)于 PropertyPlaceholderConfigurer 的配置方式,這種方式更優(yōu)雅。
<context:property-placeholder location="classpath:system.properties" file-encoding="utf-8"/>
這種方式雖然如果希望對(duì)屬性進(jìn)行加密或者使用數(shù)據(jù)庫(kù)表保存配置信息等的高級(jí)功能,就必須擴(kuò)展 PropertyPlaceholderConfigurer 的類(lèi),然后采用之前所說(shuō)的 Bean 配置方式 。
1.3 @value 方式(基于注解或 JAVA 類(lèi)的配置)
基于注解的 Bean 可以通過(guò) @Value 注解為 Bean 的成員變量或者方法入?yún)⒆詣?dòng)注入屬性值 。
@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 類(lèi)注解 @Configuration 的類(lèi)本身就標(biāo)注了 @Component,所以它引用屬性的方式和基于注解配置的引用方式是一樣的 。
注意:使用過(guò)程中要確保所引用的屬性值在屬性文件中存在并且類(lèi)型匹配,否則會(huì)拋出異常。
2 加密屬性值
對(duì)于那些不敏感的屬性信息,在屬性文件中以明文形式出現(xiàn)是合理的,但是如果屬性信息是敏感信息(比如數(shù)據(jù)庫(kù)用戶(hù)名和密碼等),建議以密文的方式保存 。 因?yàn)槿绻舾行畔⒚芪谋4?,那么任何擁有服?wù)器登陸權(quán)限的人就有可能看到機(jī)密信息,從而影響系統(tǒng)安全。
對(duì)于那些對(duì)安全要求特別高的系統(tǒng)(銀行、公安系統(tǒng)等),這些敏感信息應(yīng)該只掌握在少數(shù)特定的維護(hù)人員手里。所以,我們需要對(duì)這些信息進(jìn)行加密,Spring 容器讀取文件后,再對(duì)其進(jìn)行解密。
PropertyPlaceholderConfigurer 繼承自 PlaceholderConfigurerSupport 類(lèi),后者設(shè)計(jì)了一些方法,用于在屬性被使用之前對(duì)它們進(jìn)行轉(zhuǎn)換:
方法 | 說(shuō)明 |
---|---|
convertProperty(String propertyName, String propertyValue) | 加載并讀取每一個(gè)屬性值時(shí),都會(huì)調(diào)用此方法對(duì)其進(jìn)行轉(zhuǎn)換處理。 |
String convertPropertyValue(String originalValue) | 與前一個(gè)方法功能相似,只不過(guò)參數(shù)只傳入了屬性值。 |
void convertProperties(Properties props) | 轉(zhuǎn)換所有的屬性值。 |
默認(rèn)情況下,這三個(gè)都是空方法,我們可以擴(kuò)展 PropertyPlaceholderConfigurer ,覆蓋相應(yīng)的轉(zhuǎn)換方法,從而支持帶加密后的屬性值文件。
2.1 DES 加密解密工具類(lèi)
信息的加密分為對(duì)稱(chēng)和非對(duì)稱(chēng)兩種方式, 對(duì)稱(chēng)表示加密后的信息可以解密出來(lái),而非對(duì)稱(chēng)方式則不能根據(jù)加密后的信息解密為原值 。 MD5 屬于非對(duì)稱(chēng)加密, DES 屬于對(duì)稱(chēng)加密 。所以這里我們使用 DES 加密屬性值;讀取屬性值時(shí),再使用 DES 進(jìn)行解密 。
DES 加密解密工具類(lèi)源代碼請(qǐng)點(diǎn)擊這里。
DES 加解密使用說(shuō)明:
我們使用 DES 加解密工具,通過(guò)命令行的方式,對(duì)數(shù)據(jù)庫(kù)的賬號(hào)與密碼進(jìn)行加密;接著,把加密后的字符串寫(xiě)入 system.properties,形如:
username=q5L+2PPrsPQ= password=UdyjsvkXc/Q=
2.2 對(duì)屬性文件的值進(jìn)行加密
首先自定義屬性配置器,支持解密轉(zhuǎn)換:
public class CustomPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer { /** * DES 密鑰 */ private static final String KEY_STR = "123456"; /** * 值加密過(guò)的屬性名稱(chēng)組 */ 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 屬性名稱(chēng) * @return */ private boolean isDecrypt(String propertyName) { return ArrayUtils.contains(ENCRYPT_PROPERTY_NAMES, propertyName); } }
注意:
- 這里的 DES 密鑰必須與之前加密的密鑰相同。
- ArrayUtils 來(lái)源于 commons-lang3。
然后通過(guò) <bean> 的方式來(lái)配置自定義的屬性文件:
<bean class="net.deniro.spring4.properties.CustomPropertyPlaceholderConfigurer" p:location="classpath:system.properties" p:fileEncoding="utf-8"/>
這樣,Spring 容器就可以加載被加密過(guò)的屬性文件啦,是不是很簡(jiǎn)單呀
O(∩_∩)O哈哈~
3 對(duì)自身的引用
Spring 既允許在 Bean 定義中通過(guò) ${propName}引用屬性的值,也允許在屬性文件中使用 ${propName} 實(shí)現(xiàn)屬性之間的相互引用 。
database=spring4 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/${database}
這里通過(guò) ${database}引用了另外一個(gè)屬性的值(數(shù)據(jù)庫(kù)實(shí)例名)。因此,對(duì)于一些復(fù)雜的屬性,我們可以通過(guò)這種方式將屬性變化的部分抽取出來(lái),從而實(shí)現(xiàn)配置的最小化 。
注意:如果一個(gè)屬性值太長(zhǎng),我們可以在每一行的最后加上 “\”,就可以把屬性值劃分為多行,就像這樣:
profile.jdbc.url=jdbc:mysql://127.0.0.1:3306/dbName?useUnicode=true&characterEncoding\ =UTF-8\ &zeroDateTimeBehavior=convertToNull
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
org.apache.zookeeper.KeeperException.BadVersionException異常的解
在使用Apache ZooKeeper進(jìn)行分布式協(xié)調(diào)時(shí),你可能會(huì)遇到org.apache.zookeeper.KeeperException.BadVersionException異常,本文就來(lái)介紹一下解決方法,感興趣的可以了解一下2024-03-03Java中LinkedHashSet、LinkedHashMap源碼詳解
這篇文章主要介紹了Java中LinkedHashSet、LinkedHashMap源碼詳解,LinkedHashMap是一個(gè)以雙向鏈表的方式將Entry節(jié)點(diǎn)鏈接起來(lái)的HashMap子類(lèi),它在HashMap的基礎(chǔ)上實(shí)現(xiàn)了更多的功能,具有順序存儲(chǔ)和遍歷的特性,需要的朋友可以參考下2023-09-09SpringBoot實(shí)現(xiàn)動(dòng)態(tài)加載外部Jar流程詳解
這篇文章主要介紹了SpringBoot動(dòng)態(tài)加載外部Jar的流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-05-05DOM解析XML報(bào)錯(cuò)Content is not allowed in prolog解決方案詳解
這篇文章主要介紹了DOM解析XML報(bào)錯(cuò)解決方案詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Java設(shè)計(jì)模式中的裝飾器模式簡(jiǎn)析
這篇文章主要介紹了Java設(shè)計(jì)模式中的裝飾器模式簡(jiǎn)析,裝飾模式能夠?qū)崿F(xiàn)動(dòng)態(tài)的為對(duì)象添加功能,是從一個(gè)對(duì)象外部來(lái)給對(duì)象添加功能,通常給對(duì)象添加功能,要么直接修改對(duì)象添加相應(yīng)的功能,要么派生對(duì)應(yīng)的子類(lèi)來(lái)擴(kuò)展,抑或是使用對(duì)象組合的方式,需要的朋友可以參考下2023-12-12MyBatis-Plus自定義SQL的詳細(xì)過(guò)程記錄
Java開(kāi)發(fā)使用mybatis-plus來(lái)執(zhí)行sql操作,往往比mybatis能夠省時(shí)省力,下面這篇文章主要給大家介紹了關(guān)于MyBatis-Plus自定義SQL的相關(guān)資料,需要的朋友可以參考下2022-02-02Java Lambda表達(dá)式和函數(shù)式接口實(shí)例分析
這篇文章主要介紹了Java Lambda表達(dá)式和函數(shù)式接口,結(jié)合實(shí)例形式分析了Java8 Lambda表達(dá)式和函數(shù)式接口相關(guān)原理、用法及操作注意事項(xiàng),需要的朋友可以參考下2019-09-09Spring-Boot 集成Solr客戶(hù)端的詳細(xì)步驟
本篇文章主要介紹了Spring-Boot 集成Solr客戶(hù)端的詳細(xì)步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11Springboot通過(guò)url訪問(wèn)本地圖片代碼實(shí)例
這篇文章主要介紹了springboot通過(guò)url訪問(wèn)本地圖片代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03完美解決idea創(chuàng)建文件時(shí),文件不分級(jí)展示的情況
這篇文章主要介紹了完美解決idea創(chuàng)建文件時(shí),文件不分級(jí)展示的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02