课程咨询 :0592-5903858 QQ:1079585464

厦门达内java培训

厦门Java培训 > 达内新闻 > 达内:Java实现配置加载机制
  • 达内:Java实现配置加载机制

    发布:厦门Java培训      来源:码农网      时间:2016-01-27


  •     厦门达内java培训专家探讨加载配置中,如何把一个配置文件映射成Java里的POJO对象,并探讨如何实现不同方式的加载。

        实现这一配置加载机制后,我们希望代码更加简洁,并且可扩展,可管理。

        配置加载器

        首先,我们需要一个配置加载器,而这个配置加载器是可以有多种不同的加载方式的,因此,我们用一个接口来描述它,如下所示:

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

        可是,为什么我们需要在这个接口上声明泛型 <T> ?

        很明显,当我们要使用一个配置加载器时,你得告诉这个配置加载器你需要加载后得到什么结果。

        例如,你希望加载配置后得到一个 AppleConfig 对象,那么你就可以这么去使用上述定义的接口:

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

        于是你将配置文件里的信息转化成了一个AppleConfig对象,并且你能得到这个AppleConfig对象实例。

        由上述的情况来看,只要我们的 AppleConfigLoader 里面实现了怎么加载配置文件的具体劳动,就可以轻易加载配置了。

        可以这么说,但是配置是否可以通过不同的方式加载呢?比如通过Properties加载,通过dom方式加载,通过sax方式加载,或者通过某些第三方的开源库来加载。

        因此,除了 配置加载器 ,我们还需要另外一种角色,配置加载方式的提供者——IConfigProvider。

        配置加载方式的提供者

        配置加载方式的提供者可以提供一种加载方式给配置加载器,换言之,提供一个 对象 给配置加载器。

        如果通过dom方式加载,那么 提供者 提供一个 Document 对象给 加载器 。 

        如果通过Properties方式加载,那么 提供者 提供一个 Properties 对象给 加载器

        如果通过第三方类库提供的方式加载,比如apache-commons-digester3(tomcat的配置加载),那么 提供者 提供一个 Digester 对象给 加载器

        提供者的职责就是“提供”,仅此而已,只提供配置加载器所需要的对象,但它本身并不参与配置加载的劳动。

        我们用一个接口 IConfigProvider 来定义这个 提供者

    /**
     *
     *
     * @author Bean
     * @date 2016年1月21日 上午11:54:28
     * @version 1.0
     *
     */
    public interface IConfigProvider<T> {
        /**
         * provide a config source used for loading config
         *
         * @return
         * @throws ConfigException
         */
        public T provide() throws ConfigException;
    }

        这里为什么又会有 <T> 来声明泛型呢?

        如果需要一个提供者,那么至少得告诉这个提供者它该提供什么吧。

        因此,一个提供者会提供什么,由这个来决定。

        同时,到这里,我们可以先建造一个工厂,让它来生产特定的提供者:

    /**
     *
     *
     * @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<Document> createDocumentProvider(String filePath) {
            return new DocumentProvider(filePath);
        }
        public static IConfigProvider<Properties> createPropertiesProvider(String filePath) {
            return new PropertiesProvider(filePath);
        }
        public static IConfigProvider<Digester> createDigesterProvider(String filePath) {
                return new DigesterProvider(filePath);
        }
    }

        可以开始实现具体配置加载器了?

        还不行!

        假设我们有一个配置文件,叫apple.xml。而且我们要通过DOM方式把这一份apple.xml加载后变成AppleConfig对象。

        那么,首先我要通过提供者工厂给我制造一个能提供Document的提供者。然后拿到这个提供者,我就可以调用它的provide方法来获得Document对象,有了document对象,那么我就可以开始来加载配置了。

        可是,如果要加载BananaConfig、PearConfig…….呢,其步骤都是一样的。因此我们还要有一个抽象类,来实现一些默认的共同行为。

    /**
     *
     *
     * @author Bean
     * @date 2016年1月21日 上午11:59:19
     * @version 1.0
     *
     */
    public abstract class AbstractConfigLoader <T, U> implements IConfigLoader<T>{
        protected IConfigProvider<U> provider;
        protected AbstractConfigLoader(IConfigProvider<U> 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<U> getProvider() {
            return this.provider;
        }
    }

        每个配置加载器都有一个带参数构造器,接收一个Provider。

        泛型指明了我要加载的是AppleConfig还是BananConfig,泛型 <U> 指明了要用什么加载方式加载,是Document呢,还是Properties,或者其他。

        实战运用实例

        有一份菜市场配置文件market.xml,配置了菜市场的商品,里面有两种商品,分别是苹果和鸡蛋。

    <market>
        <apple>
            <color>red</color>
            <price>100</price>
        </apple>
        <egg>
            <weight>200</weight>
        </egg>
    </market>
        另外还有一份关于各个档口老板名字的配置文件,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<String, String> owner = new HashMap<String, String>();
        public void addOwner(String portName, String owner) {
            this.owner.put(portName, owner);
        }
        public String getOwnerByPortName(String portName) {
            return this.owner.get(portName);
        }
        public Map<String, String> getOwners() {
            return Collections.unmodifiableMap(this.owner);
        }
    }

        这个例子有两种配置加载方式,分别是Dom和Properties加载方式。

        所以我们的提供者建造工厂需要制造两种提供者provider.

        而且需要定义2个配置加载器,分别是:

    OwnerConfigLoader
    /**
     *
     *
     * @author Bean
     * @date 2016年1月21日 下午11:24:50
     * @version 1.0
     *
     */
    public class OwnerConfigLoader extends AbstractConfigLoader<OwnerConfig, Properties>{
        /**
         * @param provider
         */
        protected OwnerConfigLoader(IConfigProvider<Properties> provider) {
            super(provider);
        }
        /*
         * @see AbstractConfigLoader#load(java.lang.Object)
         */
        @Override
        public OwnerConfig load(Properties props) throws ConfigException {
            OwnerConfig ownerConfig = new OwnerConfig();
            /**
             * 利用props,设置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<MarketConfig, Document> {
        /**
         * @param provider
         */
        protected MarketConfigLoader(IConfigProvider<Document> 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
             * 所以这里要新建一个OwnerConfigLoader,委托它来加载OwnerConfig
             */
            OwnerConfigLoader ownerConfigLoader = new OwnerConfigLoader(ConfigProviderFactory.createPropertiesProvider(YOUR_FILE_PATH));
            OwnerConfig ownerConfig = ownerConfigLoader.load();
            marketConfig.setOwnerConfig(ownerConfig);
            return marketConfig;
        }
    }

        然后,我们在应用层面如何获取到MarketConfig呢
    MarketConfigLoader marketConfigLoader = new MarketConfigLoader(ConfigProviderFactory.createDocumentProvider(YOUR_FILE_PATH));
    MarketConfig marketConfig = marketConfigLoader.load();

        也许有些奇怪,明明有四个配置类,为什么只有2个配置加载器呢。因为MarketConfig、EggConfig和AppleConfig,都是从同一个xml配置文件里面加载,所以只要一个Document对象,通过MarketConfigLoader就可以全部加载。

        而OwnerConfig是不同的加载方式,所以需要另外一个加载器。

        达内java培训专家给出的配置加载机制,能够让配置加载机制更灵活,容易扩展,并且能够集成多种配置加载方式,融合到一个机制进来,发挥各自优点。






    原文链接:http://www.codeceo.com/article/java-config-load.html
    推荐文章

上一篇:达内:Java 反射机制的原理

下一篇:达内:如何入门java语言

最新开班日期  |  更多

Java--大数据周末班

Java--大数据周末班

开班日期:每周一

Java--大数据全日制班

Java--大数据全日制班

开班日期:每周一

Java--零基础周末班

Java--零基础周末班

开班日期:每周一

Java--零基础全日制班

Java--零基础全日制班

开班日期:每周一

  • 地址:厦门软件园二期望海路59号之一401达内科技
  • 课程培训电话:0592-5903858 QQ:1079585464     全国服务监督电话:400-111-8989
  • 服务邮箱 ts@tedu.cn
  • 2001-2016 达内时代科技集团有限公司 版权所有 京ICP证8000853号-56