国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java實(shí)現(xiàn)配置加載機(jī)制

zeyu / 2768人閱讀

摘要:如何實(shí)現(xiàn)這樣一個(gè)配置加載機(jī)制,讓我們擁有這個(gè)機(jī)制后,不會(huì)讓加載配置的代碼散布得到處都是,并且可擴(kuò)展,可管理。尾聲本文提出的配置加載機(jī)制,并不能夠?qū)嶋H幫忙加載配置,這事應(yīng)該留給,,以及其他一些開源庫如,去做。

前言

現(xiàn)如今幾乎大多數(shù)Java應(yīng)用,例如我們耳熟能詳?shù)膖omcat, struts2, netty...等等數(shù)都數(shù)不過來的軟件,
要滿足通用性,都會(huì)提供配置文件供使用者定制功能。

甚至有一些例如Netty這樣的網(wǎng)絡(luò)框架,幾乎完全就是由配置驅(qū)動(dòng),這樣的軟件我們也通常稱之為"微內(nèi)核架構(gòu)"的軟件。
你把它配置成什么,它就是什么。

It is what you configure it to be.

最常見的配置文件格式是XML, Properties等等文件。

本文探討加載配置中最通用也是最常見的場(chǎng)景,那就是把一個(gè)配置文件映射成Java里的POJO對(duì)象.
并探討如何實(shí)現(xiàn)不同方式的加載,例如,有一些配置是從本地XML文件里面加載的,而有一些配置需要從本地Properties文件加載,
更有甚者,有一些配置需要通過網(wǎng)絡(luò)加載配置。

如何實(shí)現(xiàn)這樣一個(gè)配置加載機(jī)制,讓我們擁有這個(gè)機(jī)制后,不會(huì)讓加載配置的代碼散布得到處都是,并且可擴(kuò)展,可管理。

配置加載器

首先,我們需要一個(gè)配置加載器,而這個(gè)配置加載器是可以有多種不同的加載方式的,因此,我們用一個(gè)接口來描述它,如下所示:

/**
 * 
 *
 * @author Bean
 * @date 2016年1月21日 上午11:47:12
 * @version 1.0
 *
 */
public interface IConfigLoader {
    
    /**
     * load the config typed by T
     *
     * @return
     * @throws ConfigException
     */
    public T load() throws ConfigException;
}

可是,為什么我們需要在這個(gè)接口上聲明泛型 ?
很明顯,當(dāng)我們要使用一個(gè)配置加載器時(shí),你得告訴這個(gè)配置加載器你需要加載后得到什么結(jié)果。
例如,你希望加載配置后得到一個(gè)AppleConfig對(duì)象,那么你就可以這么去使用上述定義的接口:

    IConfigLoader loader = new AppleConfigLoader();
    AppleConfig config = loader.load();

于是你將配置文件里的信息轉(zhuǎn)化成了一個(gè)AppleConfig對(duì)象,并且你能得到這個(gè)AppleConfig對(duì)象實(shí)例。

到目前,貌似只要我們的AppleConfigLoader里面實(shí)現(xiàn)了怎么加載配置文件的具體勞動(dòng),我們就可以輕易加載配置了。

可以這么說,但是不是還沒有考慮到,配置可能通過不同的方式加載呢,比如通過Properties加載,通過dom方式加載,通過sax方式加載,或者通過某些第三方的開源庫來加載。

因此,除了配置加載器,我們還需要另外一種角色,配置加載方式的提供者。暫且,我們就叫它IConfigProvider。

配置加載方式的提供者

配置加載方式的提供者可以提供一種加載方式給配置加載器,換言之,提供一個(gè)對(duì)象給配置加載器。

如果通過dom方式加載,那么提供者提供一個(gè)Document對(duì)象給加載器

如果通過Properties方式加載,那么提供者提供一個(gè)Properties對(duì)象給加載器

如果通過第三方類庫提供的方式加載,比如apache-commons-digester3(tomcat的配置加載),那么提供者提供一個(gè)Digester對(duì)象給加載器

提供者的職責(zé)就是提供,僅此而已,只提供配置加載器所需要的對(duì)象,但它本身并不參與配置加載的勞動(dòng)。

我們用一個(gè)接口IConfigProvider來定義這個(gè)提供者

/**
 *
 *
 * @author Bean
 * @date 2016年1月21日 上午11:54:28
 * @version 1.0
 *
 */
public interface IConfigProvider {

    /**
     * provide a config source used for loading config
     *
     * @return
     * @throws ConfigException
     */
    public T provide() throws ConfigException;
}

這里為什么又會(huì)有來聲明泛型呢?
如果需要一個(gè)提供者,那么至少得告訴這個(gè)提供者它該提供什么吧。

因此,一個(gè)提供者會(huì)提供什么,由這個(gè)來決定。

同時(shí),到這里,我們可以先建造一個(gè)工廠,讓它來生產(chǎn)特定的提供者:

/**
 *
 *
 * @author Bean
 * @date 2016年1月21日 上午11:56:28
 * @version 1.0
 *
 */
public class ConfigProviderFactory {

    private ConfigProviderFactory() {
        throw new UnsupportedOperationException("Unable to initialize a factory class : "
                + getClass().getSimpleName());
    }

    public static IConfigProvider createDocumentProvider(String filePath) {
        return new DocumentProvider(filePath);
    }

    public static IConfigProvider createPropertiesProvider(String filePath) {
        return new PropertiesProvider(filePath);
    }
    
    public static IConfigProvider createDigesterProvider(String filePath) {
            return new DigesterProvider(filePath);
    }
}
可以開始實(shí)現(xiàn)具體配置加載器了?

還不行!

到這里,假設(shè)我們有一個(gè)配置文件,叫apple.xml。而且我們要通過DOM方式把這一份apple.xml加載后變成AppleConfig對(duì)象。

那么,首先我要通過提供者工廠給我制造一個(gè)能提供Document的提供者。然后拿到這個(gè)提供者,我就可以調(diào)用它的provide方法來獲得Document對(duì)象,
有了document對(duì)象,那么我就可以開始來加載配置了。

可是,如果要加載BananaConfig、PearConfig.......呢,其步驟都是一樣的。因此我們還要有一個(gè)抽象類,來實(shí)現(xiàn)一些默認(rèn)的共同行為。

/**
 *
 *
 * @author Bean
 * @date 2016年1月21日 上午11:59:19
 * @version 1.0
 *
 */
public abstract class AbstractConfigLoader  implements IConfigLoader{

    protected IConfigProvider provider;
    
    protected AbstractConfigLoader(IConfigProvider provider) {
        this.provider = provider;
    }

    /*
     * @see IConfigLoader#load()
     */
    @Override
    public T load() throws ConfigException {
        return load(getProvider().provide());
    }

    public abstract T load(U loaderSource) throws ConfigException;
    
    protected IConfigProvider getProvider() {
        return this.provider;
    }
}

每個(gè)配置加載器都有一個(gè)帶參數(shù)構(gòu)造器,接收一個(gè)Provider。

泛型指明了我要加載的是AppleConfig還是BananConfig,泛型指明了要用什么加載方式加載,是Document呢,還是Properties,或者其他。

實(shí)戰(zhàn)運(yùn)用實(shí)例

有一份菜市場(chǎng)配置文件market.xml,配置了菜市場(chǎng)的商品,里面有兩種商品,分別是蘋果和雞蛋。


    
        red
        100
    
    
        200
    

另外還有一份關(guān)于各個(gè)檔口老板名字的配置文件,owner.properties

port1=Steve Jobs
port2=Bill Gates
port3=Kobe Bryant

我們先定義好如下類:
MarketConfig.java

/**
 *
 *
 * @author Bean
 * @date 2016年1月21日 下午11:03:37
 * @version 1.0
 *
 */
public class MarketConfig {

    private AppleConfig appleConfig;
    private EggConfig eggConfig;
    private OwnerConfig ownerConfig;
    
    public AppleConfig getAppleConfig() {
        return appleConfig;
    }
    public void setAppleConfig(AppleConfig appleConfig) {
        this.appleConfig = appleConfig;
    }
    public EggConfig getEggConfig() {
        return eggConfig;
    }
    public void setEggConfig(EggConfig eggConfig) {
        this.eggConfig = eggConfig;
    }
    public OwnerConfig getOwnerConfig() {
        return ownerConfig;
    }
    public void setOwnerConfig(OwnerConfig ownerConfig) {
        this.ownerConfig = ownerConfig;
    }
}

AppleConfig.java

/**
 *
 *
 * @author Bean
 * @date 2016年1月21日 下午11:03:45
 * @version 1.0
 *
 */
public class AppleConfig {

    private int price;
    private String color;
    
    public void setPrice(int price) {
        this.price = price;
    }
    
    public int getPrice() {
        return this.price;
    }
    
    public void setColor(String color) {
        this.color = color;
    }
    
    public String getColor() {
        return this.color;
    }
}

EggConfig.java

/**
 *
 *
 * @author Bean
 * @date 2016年1月21日 下午11:03:58
 * @version 1.0
 *
 */
public class EggConfig {

    private int weight;
    
    public void setWeight(int weight) {
        this.weight = weight;
    }
    
    public int getWeight() {
        return this.weight;
    }
}

OwnerConfig.java

/**
 *
 *
 * @author Bean
 * @date 2016年1月21日 下午11:04:06
 * @version 1.0
 *
 */
public class OwnerConfig {

    private Map owner = new HashMap();
    
    public void addOwner(String portName, String owner) {
        this.owner.put(portName, owner);
    }
    
    public String getOwnerByPortName(String portName) {
        return this.owner.get(portName);
    }
    
    public Map getOwners() {
        return Collections.unmodifiableMap(this.owner);
    }
}

這個(gè)例子有兩種配置加載方式,分別是Dom和Properties加載方式。
所以我們的提供者建造工廠需要制造兩種提供者provider.
而且需要定義2個(gè)配置加載器,分別是:

OwnerConfigLoader

/**
 *
 *
 * @author Bean
 * @date 2016年1月21日 下午11:24:50
 * @version 1.0
 *
 */
public class OwnerConfigLoader extends AbstractConfigLoader{

    /**
     * @param provider
     */
    protected OwnerConfigLoader(IConfigProvider provider) {
        super(provider);
    }

    /* 
     * @see AbstractConfigLoader#load(java.lang.Object)
     */
    @Override
    public OwnerConfig load(Properties props) throws ConfigException {
        OwnerConfig ownerConfig = new OwnerConfig();
        
        /**
         * 利用props,設(shè)置ownerConfig的屬性值
         * 
         * 此處代碼省略
         */
        return ownerConfig;
    }
}

然后是MarketConfigLoader

import org.w3c.dom.Document;

/**
 *
 *
 * @author Bean
 * @date 2016年1月21日 下午11:18:56
 * @version 1.0
 *
 */
public class MarketConfigLoader extends AbstractConfigLoader {

    /**
     * @param provider
     */
    protected MarketConfigLoader(IConfigProvider provider) {
        super(provider);
    }

    /* 
     * AbstractConfigLoader#load(java.lang.Object)
     */
    @Override
    public MarketConfig load(Document document) throws ConfigException {
        
        MarketConfig marketConfig = new MarketConfig();
        AppleConfig appleConfig = new AppleConfig();
        EggConfig eggConfig = new EggConfig();
        /**
         * 在這里處理document,然后就能得到
         * AppleConfig和EggConfg
         * 
         * 此處代碼省略
         */
        marketConfig.setAppleConfig(appleConfig);
        marketConfig.setEggConfig(eggConfig);
        
        /**
         * 由于OwnerConfig是需要properties方式來加載,不是xml
         * 所以這里要新建一個(gè)OwnerConfigLoader,委托它來加載OwnerConfig
         */
        
        OwnerConfigLoader ownerConfigLoader = new OwnerConfigLoader(ConfigProviderFactory.createPropertiesProvider(YOUR_FILE_PATH));
        OwnerConfig ownerConfig = ownerConfigLoader.load();
        
        marketConfig.setOwnerConfig(ownerConfig);
        
        return marketConfig;
    }
}

然后,我們?cè)趹?yīng)用層面如何獲取到MarketConfig呢

MarketConfigLoader marketConfigLoader = new MarketConfigLoader(ConfigProviderFactory.createDocumentProvider(YOUR_FILE_PATH));
MarketConfig marketConfig = marketConfigLoader.load();

也許有個(gè)地方會(huì)人奇怪,明明有四個(gè)配置類,為什么只有2個(gè)配置加載器呢。
因?yàn)镸arketConfig、EggConfig和AppleConfig,都是從同一個(gè)xml配置文件里面加載,所以只要一個(gè)Document對(duì)象,通過MarketConfigLoader就可以全部加載。

而OwnerConfig是不同的加載方式,所以需要另外一個(gè)加載器。

尾聲

本文提出的配置加載機(jī)制,并不能夠?qū)嶋H幫忙加載配置,這事應(yīng)該留給DOM,SAX,以及其他一些開源庫如dom4j,Digester去做。
但本文提出的配置加載機(jī)制能夠讓配置加載機(jī)制更靈活,容易擴(kuò)展,并且能夠集成多種配置加載方式,融合到一個(gè)機(jī)制進(jìn)來,發(fā)揮各自有點(diǎn)。

實(shí)際上,有些軟件經(jīng)常需要同時(shí)從多種不同格式的配置文件里面加載配置,例如struts2,以及我最近在研究并被氣到吐血的某國(guó)產(chǎn)開源數(shù)據(jù)庫中間件軟件,
如果沒有一套完整的配置加載機(jī)制,那么代碼會(huì)比較散亂,可維護(hù)性不高。容易使人吐血。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/65382.html

相關(guān)文章

  • 聊聊Dubbo - Dubbo可擴(kuò)展機(jī)制實(shí)戰(zhàn)

    摘要:今天我想聊聊的另一個(gè)很棒的特性就是它的可擴(kuò)展性。的擴(kuò)展機(jī)制在的官網(wǎng)上,描述自己是一個(gè)高性能的框架。接下來的章節(jié)中我們會(huì)慢慢揭開擴(kuò)展機(jī)制的神秘面紗。擴(kuò)展擴(kuò)展點(diǎn)的實(shí)現(xiàn)類。的定義在配置文件中可以看到文件中定義了個(gè)的擴(kuò)展實(shí)現(xiàn)。 摘要: 在Dubbo的官網(wǎng)上,Dubbo描述自己是一個(gè)高性能的RPC框架。今天我想聊聊Dubbo的另一個(gè)很棒的特性, 就是它的可擴(kuò)展性。 Dubbo的擴(kuò)展機(jī)制 在Dub...

    techstay 評(píng)論0 收藏0
  • java加載相關(guān)

    摘要:標(biāo)準(zhǔn)擴(kuò)展類加載器,它負(fù)責(zé)加載或由系統(tǒng)變量指定位置中的類庫加載到內(nèi)存中。系統(tǒng)類加載器,它負(fù)責(zé)將類路徑中的類庫加載到內(nèi)存。 類加載機(jī)制大家應(yīng)該已經(jīng)非常熟悉了,采取雙親委派機(jī)制,當(dāng)加載一個(gè)類時(shí),首先將加載任務(wù)委托給父類加載器,依次遞歸,如果父類加載器可以完成加載任務(wù),就成功返回;如果父類無法加載,才由自己加載。 雙親委派機(jī)制的作用:防止內(nèi)存中出現(xiàn)多份相同的字節(jié)碼。 其他規(guī)則:1.隱式加載:...

    el09xccxy 評(píng)論0 收藏0
  • Reflection:Java反射機(jī)制的應(yīng)用場(chǎng)景

    近期在維護(hù)公司項(xiàng)目的時(shí)候遇到一個(gè)問題,因?yàn)閷?shí)體類中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對(duì)象賦值的過程中不能夠使用 set 方法,為了實(shí)現(xiàn)功能,所以采用了反射的機(jī)制給對(duì)象屬性賦值,借此機(jī)會(huì)也了解了反射的一些具體用法和使用場(chǎng)景,分以下兩點(diǎn)對(duì)反射進(jìn)行分析: 反射的優(yōu)勢(shì)和劣勢(shì) 反射的應(yīng)用場(chǎng)景 反射的優(yōu)勢(shì)和劣勢(shì) ??個(gè)人理解,反射機(jī)制實(shí)際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式...

    浠ラ箍 評(píng)論0 收藏0
  • dubbo之SPI

    摘要:簡(jiǎn)介全稱為,是一種服務(wù)發(fā)現(xiàn)機(jī)制。的本質(zhì)是將接口實(shí)現(xiàn)類的全限定名配置在文件中,并由服務(wù)加載器讀取配置文件,加載實(shí)現(xiàn)類。不過,并未使用原生的機(jī)制,而是對(duì)其進(jìn)行了增強(qiáng),使其能夠更好的滿足需求。并未使用,而是重新實(shí)現(xiàn)了一套功能更強(qiáng)的機(jī)制。 1、SPI簡(jiǎn)介 SPI 全稱為 Service Provider Interface,是一種服務(wù)發(fā)現(xiàn)機(jī)制。SPI 的本質(zhì)是將接口實(shí)現(xiàn)類的全限定名配置在文件中...

    UnixAgain 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

zeyu

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<