Hadoop Configuration配置类的分析(二)

2015-01-27 06:00:05 · 作者: · 浏览: 25
ecifies whether to load from the default files */ public Configuration(boolean loadDefaults) { this.loadDefaults = loadDefaults; if (LOG.isDebugEnabled()) { LOG.debug(StringUtils.stringifyException(new IOException("config()"))); } synchronized(Configuration.class) { //加载过的Configuration对象对会加入到REGISTRY集合中 REGISTRY.put(this, null); } this.storeResource = false; }重点观察人家把当前初始化的Configuration类加入到全局REGISTRY里面了。

以上分析的代码都是前期的操作,那么比较关键的set/get这类和属性直接相关的方法怎么实现的,所以这个时候,必须要先了解Hadoop中的配置文件是怎样的格式存在于文件中的。比如HDFS的配置文件hdfs-site.xml;

           

           


           


            

  
             
             
              dfs.name.dir
              
             
              /var/local/hadoop/hdfs/name
              
             
              Determines where on the local filesystem the DFS name node should store the name table. If this is a comma-delimited list of directories then the name table is replicated in all of the directories, for redundancy. 
              
             
              true
              
            

  
             
             
              dfs.data.dir
              
             
              /var/local/hadoop/hdfs/data
              
             
              Determines where on the local filesystem an DFS data node should store its blocks. If this is a comma-delimited list of directories, then data will be stored in all named directories, typically on different devices. Directories that do not exist are ignored. 
              
             
              true
              
            
.......
           
节点层级的关系不是很复杂,关键在每个Property节点保留name名字,value值,des对于此属性的描述,final标签用于判断此属性能不能被改变,为true代表无法变更,类似于java语言里的final关键字。了解完配置文件的结构之后,就可以继续往下看了,比如我要设置1个属性,set的一个小小的方法如下:

/** 
   * Set the value of the name property.
   * 
   * @param name property name.
   * @param value property value.
   * 根据name设置属性值,属性键值对保存在property中
   */
  public void set(String name, String value) {
    getOverlay().setProperty(name, value);
    getProps().setProperty(name, value);
  }
后面的setProperty就是Property的设置方法,jdk的API,所以关键就是前面获取getProps的方法,如何把文件中的属性加载到Property的变量中的。
/**
   * 加载的时候采用了延时加载的策略
   * @return
   */
  private synchronized Properties getProps() {
    if (properties == null) {
      properties = new Properties();
      //从资源中再次获取属性相关的数据
      loadResources(properties, resources, quietmode);
      if (overlay!= null) {
        properties.putAll(overlay);
        if (storeResource) {
          for (Map.Entry
           
             item: overlay.entrySet()) {
            updatingResource.put((String) item.getKey(), "Unknown");
          }
        }
      }
    }
    return properties;
  }
           
看了上面为NULL的判断,也许你就知道为什么刚刚的重新加载操作那么简单,就执行了clear操作就完了,就是等着后面真正要获取这个Property的时候在加载的,就是所谓的延时加载策略,类似于单例模式中的懒汉式模型。所以loadResources又是此实现的关键:

private void loadResource(Properties properties, Object name, boolean quiet) {
    try {
      //工厂模式获取解析xml文件对象,这里用的是doc解析方式
      DocumentBuilderFactory docBuilderFactory 
        = DocumentBuilderFactory.newInstance();
      //ignore all comments inside the xml file
      docBuilderFactory.setIgnoringComments(true);

      //allow includes in the xml file
      docBuilderFactory.setNamespaceAware(true);
      try {
          docBuilderFactory.setXIncludeAware(true);
      } catch (UnsupportedOperationException e) {
        LOG.error("Failed to set setXIncludeAware(true) for parser "
                + docBuilderFactory
                + ":" + e,
                e);
      }
      DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
      .....

      if (root == null) {
    	//获取xml中的节点进行获取,这里先获取了根节点
        root = doc.getDocumentElement();
      }
      if (!"configuration".equals(root.getTagName()))
        LOG.fatal("bad conf file: top-level element not 
           
            ");
      NodeList props = root.getChildNodes();
      for (int i = 0; i < props.getLength(); i++) {
        Node propNode = props.item(i);
        if (!(propNode instanceof Element))
          continue;
        Element prop = (Element)propNode;
        if ("configuration".equals(prop.getTagName())) {
          //如果子节点是configuration,则再次递归调用loadResource()方法
          loadResource(properties, prop, quiet);
          continue;
        }
        if (!"property".equals(prop.getTagName()))
          LOG.warn("bad conf file: element not 
            
             "); NodeList fields = prop.getChildNodes(); String attr = null; String value = null; boolean finalParameter = false; for (int j = 0; j < fields.getLength(); j++) { Node fieldNode = fields.item(j); if (!(fieldNode instanceof Element)) continue; //属性节点分3种判断,name,value,final Element field = (Element)fieldNode; if ("name".equals(field.getTagName()) && field.hasChildNodes()) attr = ((Text)field.getFirstChild()).getData().trim(); if ("value".equals(field.getTagName()) && field.hasChildNodes()) value = ((Text)field.getFirstChild()).getData(); if ("final".equals(field.getTagName()) && field.hasChildNodes()) //final参数需额外添加到finalParameters参数的集合中 finalParameter = "true".equals(((Text)field.getFirstChild()).getData()); } // Ignore this parameter if it has already been marked as 'final' if (attr != null) { if (value != null) { if (!finalParameters.contains(attr)) { //在这步把上面去的值放入properties属性中 properties.setProperty(attr, value); if (storeResource) { updatingResource.put(attr, name.toString()); } } else if (!value.equals(properties.getProperty(attr))) { LOG.warn(name+":a attempt to override final parameter: "+attr +"; Ignoring."); } } if (finalParameter) { finalParameters.add(attr); } } }
            
           
和上面我们看的实际配置文件一对照,就不难理解了,就是简单的doc解析xml文件,这里不过多了一些处理,比如final的参数要额外再做一下操作。加载完成之后,属性信息就被放到了Property中了,就达成了目标了。

下面我们说说get的属性获取操作,同样有别样的设计,他可不仅仅是getProps().get(name)这样的操作