Commons Configuration之二基本特性和AbstractConfiguration

Configuration接口定義一大堆方法。一切從頭開始實現這些方法很是困難。由於AbstractConfiguration類存在。該類在Commons Configuration中充當大多數Configuration實現的共同基類並提供了接口須要的大量功能。所以建立一個自定義Configuration實現該類將是一個很好的起點。
除了基本實現聲明在Configuration接口中的方法以外,AbstractConfiguration類提供一些其它的便利特性。由於該類是在Commons Configuration類層次結構的根,這些特性對該類庫提供的Configuration接口的大多數特定實現都是有效的。java

1    處理缺失屬性

若是你傳入一個鍵給它的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

2    List處理

使用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實例的字符串屬性的切分。

3    變量插值

若是你熟悉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

若是一個變量不能解析,例如,由於名稱無效或未知前綴,它不能被替換,但返回包括美圓符號和大括號。

3    自定義插值

本節闡述你如何添加本身的插值。使用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()方法建立。經過覆蓋該方法可能更深刻的干預插值機制。例如自定義實現能添加更高級的查詢對象到插入器。

4    使用表達式(此處沒有明白如何使用,請高人指點一二)

除了前面描述的簡單的查找機制,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>

相關文章
相關標籤/搜索