[享學Netflix] 六、Apache Commons Configuration2.x快速構建工具Parameters和Configurations

極致之路,沒有銀彈。不要想着一招斃命,一口吃成個胖子,而是要審時度勢,結合當前狀況來裁定。

–> 返回專欄總目錄 <–
代碼下載地址:https://github.com/f641385712/netflix-learning

前言

上篇文章完整的介紹了Commons Configuration的Builder機制,並且輔以示例介紹瞭如何使用。

Commons Configuration2.x推薦我們使用Builder去構建一個Configuration實例,但奈何實際使用起來着實比較麻煩,怎麼破?
本文將介紹兩個“工具類”:ParametersConfigurations,分別能夠簡化你對參數的構建和對Builder構建器創建過程,當然還包含一步到位的直接構建出Configuration實例的方法。

說明:說這兩個API是工具類有點牽強,畢竟方法都不是static靜態方法~


正文

構建一個BuilderParameters或者一個Configuration的步驟是較爲繁瑣的,這兩個API就是爲簡化這些步驟而生。

說明:Xxxs結尾經常用於表示幫助類、工具類,形如Collections、Arrays等等…


Parameters

一個工具類,用於創建用於初始化的參數對象配置生成器對象。
與它相關的還有兩個API需要先行介紹:DefaultParametersHandlerDefaultParametersManager


DefaultParametersHandler

用於設置特定的默認值的接口。

public interface DefaultParametersHandler<T> {
	void initializeDefaults(T parameters);
}

這個接口很簡單:爲指定參數T設置默認值。它有唯一實現類CopyObjectDefaultHandler用於給BuilderParameters設置默認值。

說明:CopyObjectDefaultHandler雖然是內置的唯一實現類,但是並沒有被系統用到過,使用者可按需自取

public class CopyObjectDefaultHandler implements DefaultParametersHandler<Object> {

	private final BuilderParameters source;
	... // 省略構造器和get方法


    @Override
    public void initializeDefaults(final Object parameters) {
        try {
            BeanHelper.copyProperties(parameters, getSource().getParameters());
            BeanHelper.copyProperties(parameters, getSource());
        } catch (final Exception e) {
            throw new ConfigurationRuntimeException(e);
        }
    }
}

CopyObjectDefaultHandler處理方式:僅僅只是把你傳進來的BuilderParameters作爲source,通過反射覆制到目標Object身上而已(注意:目標是Object,而非必須BuilderParameters),個人覺得基本沒啥卵用。


DefaultParametersManager

它是用於管理DefaultParametersHandler們的管理器,因爲對於一個Class類型上可以有多個DefaultParametersHandler作用於它的,所以又抽象出DefaultHandlerData來加以管理,並且還加入了處理繼承、接口實現的匹配的能力(大多情況亦無需關心)。

public class DefaultParametersManager {
	
	// 管理着DefaultParametersHandler的集合
	private final Collection<DefaultHandlerData> defaultHandlers;
	// 線程安全
    public DefaultParametersManager() {
        defaultHandlers = new CopyOnWriteArrayList<>();
    }
    ...

	// 向管理器註冊一個DefaultParametersHandler
    public <T> void registerDefaultsHandler(final Class<T> paramsClass, final DefaultParametersHandler<? super T> handler, final Class<?>  startClass) {
    	...
    	defaultHandlers.add(new DefaultHandlerData(handler, paramsClass, startClass));
    }
    ... // 省略unregisterDefaultsHandler方法

	// 這是它最重要的一個方法:給BuilderParameters設置初始化值
	// 這時候註冊在它上面的所有的`DefaultParametersHandler#initializeDefaults`都會執行
	// 該方法在代理對象創建完成後,立馬會執行initializeParameters方法完成初始化
    public void initializeParameters(final BuilderParameters params) {
        if (params != null) {
            for (final DefaultHandlerData dhd : defaultHandlers) {
                dhd.applyHandlerIfMatching(params);
            }
        }
    }
}

對於每個Class類型是可以有多個DefaultParametersHandler爲它設置默認值的,initializeParameters()方法會在每次代理對象創建後,完成初始化賦值操作,也算是給調用者留的一個鉤子。


介紹完兩個前置API,下面正式看看Parameters提供的API們,我截圖如下:

在這裏插入圖片描述
部分源碼解讀:

Parameters:

	// 爲指定類型配置一個DefaultParametersHandler,用於自動設置初始值
    public <T> void registerDefaultsHandler(final Class<T> paramsClass, final DefaultParametersHandler<? super T> handler) {
        getDefaultParametersManager().registerDefaultsHandler(paramsClass, handler);
    }


	// 因BasicXXX不是抽象類,所以直接new即可得到實例
    public BasicBuilderParameters basic() {
        return new BasicBuilderParameters();
    }
    // 請注意:返回的是這個接口的JDK動態代理對象~~~
    public FileBasedBuilderParameters fileBased() {
        return createParametersProxy(new FileBasedBuilderParametersImpl(), FileBasedBuilderParameters.class);
    }
    public CombinedBuilderParameters combined() { ... }
    ...
    public XMLBuilderParameters xml()
    public PropertiesBuilderParameters properties()
    ...

精妙之處在於:XMLBuilderParameters/XMLBuilderParameters這些均是接口,這裏通過Parameters生成代理,使得這些接口便可直接使用了,非常方面。這種通用設計(代理對象的生成)是非常值得點讚的~

FileBasedBuilderParametersFileBasedBuilderParametersImpl的區別

  1. 後者並不是前者(接口的實現類),即使命名上看其起來非常像
  2. 兩者均實現了接口FileBasedBuilderPropertiesBasicBuilderProperties,可以設置FileBased屬性和基本屬性
  3. 兩者均是BuilderParameters的實現

總的來說,兩者功能相似,FileBasedBuilderParameters需要結合Parameters一起使用,而後者使用者可單獨使用。


使用示例

非常經典的使用案例:

@Test
public void fun4() throws ConfigurationException {
    FileBasedConfigurationBuilder<PropertiesConfiguration> builder = new FileBasedConfigurationBuilder<>(PropertiesConfiguration.class);
    Parameters params = new Parameters();

    // 配置一個FileBased參數即可
    FileBasedBuilderParameters builderParameters = params.fileBased().setThrowExceptionOnMissing(true)
            .setEncoding("UTF-8")
            .setListDelimiterHandler(new DefaultListDelimiterHandler(','))
            .setFileName("1.properties");
    builder.configure(builderParameters);

	System.out.println(builderParameters.getClass());
    ConfigurationUtils.dump(builder.getConfiguration(),System.out);
}

控制檯打印:

class com.sun.proxy.$Proxy4 // 可以看到 builderParameters是個JDK代理對象哦
common.name=YourBatman
common.age=18
common.addr=China
common.count=4
common.fullname=${common.name}-Bryant
java.version=1.8.123

至少可以看到,在參數構建BuilderParameters方面,比之前優雅了很多。


Configurations

如果Parameters你感覺離得稍遠,那麼Configurations這個類你不應該陌生。

它也是,一個工具類,它簡化了標準配置的創建和他們的Builder們。也就是說它能方便的創建builder實例,也能一步到位的方便創建出Configuration實例。

部分源碼解讀:

public class Configurations {

	// BuilderParameters等等統一交給它來構建嘍
	private final Parameters parameters;
	... // 省略構造器

	// 快速構建出一個FileBasedConfigurationBuilder實例
	// 它可以構建出形如PropertiesConfiguration
    public <T extends FileBasedConfiguration> FileBasedConfigurationBuilder<T> fileBasedBuilder(final Class<T> configClass, final File file) {
        return createFileBasedBuilder(configClass, fileParams(file));
    }
    ... // 省略重載方法

	// 注意和上面的區別哦:此處一步到位,返回的就是一個Configuration實例
    public <T extends FileBasedConfiguration> T fileBased(final Class<T> configClass, final String path) throws ConfigurationException {
        return fileBasedBuilder(configClass, path).getConfiguration();
    }

	... // 同理還有如下搭配
	// propertiesBuilder()/properties()
	// xmlBuilder()/xml()
	// iniBuilder()/ini()
	// combinedBuilder()/combined()
}

源碼解讀夠直接、夠簡單,因爲這個工具類沒太好好說的,看個使用示例一學便會。


使用示例

@Test
public void fun5() throws ConfigurationException {
    // 當然,絕大多數情況下,空構造new Configurations()即可
    // Parameters params = new Parameters();
    // Configurations configs = new Configurations(params);

    Configurations configs = new Configurations();
    PropertiesConfiguration configuration = configs.properties("1.properties");
    ConfigurationUtils.dump(configuration,System.out);
}

運行程序,控制檯打印同上。


總結

關於Commons Configuration2.x快速構建工具類Parameters和Configurations就介紹到這了,看完之後有木有一種爽感,編碼過程再一次得到了解放有木有~

分隔線

聲明

原創不易,碼字不易,多謝你的點贊、收藏、關注。把本文分享到你的朋友圈是被允許的,但拒絕抄襲。你也可【左邊掃碼/或加wx:fsx641385712】邀請你加入我的 Java高工、架構師 系列羣大家庭學習和交流。
往期精選

發佈了300 篇原創文章 · 獲贊 461 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章