Configuration接口定義一大堆方法。一切從頭開始實現這些方法很是困難。由於AbstractConfiguration類存在。該類在Commons Configuration中充當大多數Configuration實現的共同基類並提供了接口須要的大量功能。所以建立一個自定義Configuration實現該類將是一個很好的起點。
除了基本實現聲明在Configuration接口中的方法以外,AbstractConfiguration類提供一些其它的便利特性。由於該類是在Commons Configuration類層次結構的根,這些特性對該類庫提供的Configuration接口的大多數特定實現都是有效的。java
若是你傳入一個鍵給它的get方法之一,不能映射到一個已存在的屬性,配置對象該作什麼?AbstractConfiguration實現的默認行爲是若是返回值是對象類型返回null。對於原始類型做爲返回null(或任意特定值)是不可能的,所以,在這種狀況下一個NoSuchElementException拋出:apache
// 若是沒有鍵爲"NonExistingProperty"的屬性將返回null
String strValue = config.getString("NonExistingProperty");
// 若是沒有鍵爲"NonExistingProperty"的屬性將拋出一個NoSuchElementException異常
long longValue = config.getLong("NonExistingProperty");
數組
對於對象類型,像String、BigDecimal或BigInteger這種默認行爲能夠改變:若是setThrowExceptionOnMissing()方法使用一個true參數調用,這些方法將像原始類型同樣,若是傳入的屬性鍵不能解析拋出一個異常。app
注意:不幸的是支持throwExceptionOnMisssing屬性不老是一致:getList()和getStringArray()不計算該標記,若是請求屬性沒有找到返回一個空list或數組。也許這種行爲將在將來的重要版本改變。
ide
使用Configuration接口定義的getList()和getStringArray()方法處理多值屬性。當一個配置源(例如properties文件、XML文檔或JNDI上下文)處理相應Configuration實現發現這麼一個有多個值的屬性並確保該數據正確存儲。ui
當修改屬性時,AbstractConfiguration的addProperty()和setProperty()方法也實現特定list處理。傳入這些方法的屬性值能夠是list或數組產生一個多值屬性。若是屬性值是字符串,它檢測是否字符串包含list分隔符。若是是這種狀況,字符串被分割,而且它單個部分被添加。list分隔符默認是逗號。當配置源被加載時,它在考慮以內(例如,屬性的字符串值將被檢測是否包含分隔符)。經過使用setListDelimiter()方法你能設置它爲一個不一樣的字符。spa
// 改變list分隔符爲斜線
config.setListDelimiter('/');
// 如今添加一些屬性
config.addProperty("greeting", "Hello, how are you?");
config.addProperty("colors.pie", new String[] { "#FF0000", "#00FF00", "#0000FF" });
config.addProperty("colors.graph", "#808080/#00FFCC/#6422FF");
// 訪問數據
String salut = config.getString("greeting");
List<Object> colPie = config.getList("colors.pie");
String[] colGraph = config.getStringArray("colors.graph");
String firstPieColor = config.getString("colors.pie");
.net
在該例子中,list分隔符從逗號變爲斜線。由於greeting屬性沒有分割,而是保存爲單個字符串。做爲字符串傳入的colors.graph屬性相反包含新的分隔符所以產生一個三個值的屬性。注意,list是Object類型。這是由於不知道屬性值的具體類型。例如,若是你調用addProperty("answer", 42),一個Integer對象將存儲在配置中。xml
感興趣的是例子片斷的最後一行。調用的getString()方法有多個值。這將返回list的第一個值。對象
若是你想要改變全部配置對象的list分隔符,你可使用AbstractConfiguration的靜態setDefaultListDelimiter()方法。也能夠經過調用使用true的setDelimiterParsingDisabled()方法禁用全部的Configuration實例的字符串屬性的切分。
若是你熟悉Ant或Maven,你確定已經遇到了變量(像,${token})當配置文件被加載時,變量被自動解釋。Commons Configuration也支持這些特性。
application.name = Killer App
application.version = 1.6.2
application.title = ${application.name} ${application.version}
若是你如今檢索application.title的屬性值,結果將是Killer App 1.6.2。以致於每一個默認變量被解釋爲其它屬性的鍵。這只是特殊的狀況,變量名的通用語法是${prefix:name}。prefix告訴Commons Configuration變量在某一上下文中計算。咱們能夠看到,若是prefix缺失,上下文是當前配置實例。如下是默認支持的prefix名稱。
前綴 |
描述 |
sys |
該前綴標記一個變量是系統屬性。Commons Configuration將使用指定名稱搜索一個系統屬性並經過該值替換變量。這很是容易的在每一個配置實現中訪問系統屬性的值。 |
const | const前綴表示一個變量解釋爲一個類的常量成員字段(例如,使用static final修飾符的字段)。變量的名字必須是<徹底限定類名>.<字段名>的形式。指定類將被加載而且該字段的值將被獲取。 |
env | 變量也能引用特定OS環境變量。這經過evn前綴表示。 |
下面是一些例子,只針對Properties文件:
PropertiesConfiguration cfg = new PropertiesConfiguration("cfg/basic/vm.properties");
System.out.println(cfg.getString("vm.name"));
System.out.println(cfg.getString("vm.author"));
System.out.println(cfg.getString("vm.home"));
System.out.println(cfg.getString("vm.bin"));public interface Const {
public static final String AUTHOR = "Evan";
}
#至關於System.getProperty("java.runtime.name")
vm.name=${sys:java.runtime.name}
vm.author=${const:cfg.basic.Const.AUTHOR}#至關於System.getEnv("JAVA_HOME")
vm.home=${env:JAVA_HOME}
vm.bin=${vm.home}\bin
若是一個變量不能解析,例如,由於名稱無效或未知前綴,它不能被替換,但返回包括美圓符號和大括號。
本節闡述你如何添加本身的插值。使用Commons Lang的text包下的StrSubstitutor類實現插值引擎。該類使用派生自StrLookup類的對象解析變量。StrLookup定義簡單lookup()方法必須經過自定義實現;它指望變量名做爲參數並返回相應的值(更多細節能夠在Commons Lang的文檔中找到)。咱們已經介紹了標準的前綴變量,到目前爲止咱們確實已經實現派生自StrLookup的特定類。
如今能夠建立你本身的StrLookup實現並使它在一個自定義前綴上對全部配置對象有效。咱們將介紹如何實現。第一步是建立一個新類派生StrLookup,必須實現lookup()方法。做爲一個例子,咱們實現一個簡單的查詢對象僅僅返回一個傳入的變量的回執:
import org.apache.commons.lang.text.StrLookup;
public class EchoLookup extends StrLookup
{
public String lookup(String varName)
{
return "Value of variable " + varName;
}
}
如今,咱們想要該類使用前綴echo調用變量。爲了這個目的EchoLookup類必須在ConfigurationInterpolator類使用指望前綴註冊。 ConfigurationInterpolator在Commons Lang定義的StrLookup API中實現一個簡單的包裝器。它有一個靜態registerGlobalLookup()方法,咱們必須以下調用:
// 放置該代碼在你的應用程序初始化的地方
ConfigurationInterpolator.registerGlobalLookup("echo", new EchoLookup());
每一個在該行代碼以後建立的AbstractConfiguration對象將包含新的查詢類並能所以解析${echo:my_variable}形式的變量。
每一個AbstractConfiguration實例關聯一個ConfigurationInterpolator對象。該對象在第一次訪問插值特性之一時經過createInterpolator()方法建立。經過覆蓋該方法可能更深刻的干預插值機制。例如自定義實現能添加更高級的查詢對象到插入器。
除了前面描述的簡單的查找機制,Commons Configuration提供ExprLookup,使用Apache Commons Jexl容許表達式解析是否一個StrLookup被容許。若是ExprLookup被配置,該例子顯示顯示獲取系統屬性的替代方式。
user.file = ${expr:System.getProperty("user.home"}/settings.xml
ExprLookup默認被禁用,必須經過DefaultConfigurationBuilder手動添加或配置。使用Maven 2構建並引用Commons Configuration將不包括Jexl依賴,所以若是該特性被使用必須手動添加依賴到項目。
使用DefaultConfigurationBuilder添加ExprLookup是直接的。
<configuration>
<header>
<result/>
<lookups>
<lookup config-prefix="expr"
config-class="org.apache.commons.configuration.interpol.ExprLookup">
<variables>
<variable name="System" value="Class:java.lang.System"/>
<variable name"net" value="Class:java.net.InetAddress"/>
<variable name="String" value="Class:org.apache.commons.lang.StringUtils"/>
</variables>
</lookup>
</lookups>
</header>
<override>
<xml fileName="${expr:System.getProperty('basePath') +
String.lowercase(net.localHost.hostName) + '/testMultiConfiguration_default.xml'}"
config-name="defaultConfig" delimiterParsingDisabled="true">
</xml>
</override>
</configuration>
上面的例子顯示如何在表達式計算期間調用靜態方法。下一個例子顯示使用下級查詢混合表達式計算獲取「basePath」系統屬性。注意獲取系統屬性和以前例子的差別。
<configuration> <header> <result/> <lookups> <lookup config-prefix="expr" config-class="org.apache.commons.configuration.interpol.ExprLookup"> <variables> <variable name"net" value="Class:java.net.InetAddress"/> <variable name="String" value="Class:org.apache.commons.lang.StringUtils"/> </variables> </lookup> </lookups> </header> <override> <xml fileName="${expr:$[sys:basePath] + String.lowercase(net.localHost.hostName) + '/testMultiConfiguration_default.xml'}" config-name="defaultConfig" delimiterParsingDisabled="true"> </xml> </override></configuration>