hadoop系列之Configuration类解析

前言

Configuration是hadoop中五大组件的公用类,所以放在了core下,org.apache.hadoop.conf.Configruration。这个类是作业的配置信息类,任何作用的配置信息必须通过Configuration传递,因为通过Configuration可以实现在多个mapper和多个reducer任务之间共享信息。hadoop作为Apache旗下hadoop系列最早出现的组件,该组件的核心类Configuration对后续出现的hbase,have,spark的配置都有一定的借鉴意义。

概述

Configuration类最重要的作用是传递配置信息,所以其重要的属性应该是成员变量而非成员函数。

  1. resources 资源列表,用来存储配置文件名
  2. loadDefaults bool值,用来存储是否读取默认配置。默认是true
  3. REGISTRY hashmap,作用未知
  4. defaultResources 资源列表 默认的配置
  5. storeResource bool值 是否备份用户设置的配置信息到overlay
  6. updatingResource hashmap 本进程修改过的配置信息
  7. properties 最终的配置信息
  8. overlay 存放用户设置的配置信息(不包括配置文件的配置信息)

类初始化

我们按着类加载顺序和类实例化顺序来分析

1. 静态变量和静态代码块

静态代码块在defaultResources里添加了两个资源名:

    addDefaultResource("core-default.xml");
    addDefaultResource("core-site.xml");
  public static synchronized void addDefaultResource(String name) {
    if(!defaultResources.contains(name)) {
      defaultResources.add(name);
      for(Configuration conf : REGISTRY.keySet()) {
        if(conf.loadDefaults) {
          conf.reloadConfiguration();
        }
      }
    }
  }

2.非静态变量和非静态代码块

这里只是初始化了类加载器,并没有加载属性

  private ClassLoader classLoader;
  {
    classLoader = Thread.currentThread().getContextClassLoader();
    if (classLoader == null) {
      classLoader = Configuration.class.getClassLoader();
    }
  }

3. 构造函数

Configruration类有四个构造函数。构造函数并没有加载任何配置信息。
构造函数的作用有:
初始化loadDefaults
初始化REGISTRY
初始化storeResource
在这里插入图片描述

tips:

构造函数

  1. 当一个对象被创建时,系统会为这个实例的变量进行默认初始化。如果想改变这种默认的初始化,就需要用构造器来实现。
  2. 如果java没有提供任何构造函数,则系统会为java提供一个无参的构造函数。这个函数的函数体为空。因此可以说:java类至少包含一个构造函数。
  3. 当自定义构造函数之后,默认构造函数就不可再使用。如果不重新定义参数为空的构造函数,则无法使用" 类名(空)"实例化对象。

类加载顺序

https://blog.csdn.net/weixin_37275456/article/details/100594486

配置加载

1. 分析

到目前为止尚未发现有任何加载配置的迹象。也就是说类初始化之后如果没有任何配置信息。是一个空非配置类。那什么时候加载配置文件的呢?
答:第一次从配置类里获取配置信息的时候。例如调用:

public int getInt(String name, int defaultValue)
public long getLong(String name, long defaultValue)
public int getInt(String name, int defaultValue)
。。。

上面这些函数都直接或者间接的调用了下面这个函数

  public String get(String name) {
    return substituteVars(getProps().getProperty(name));
  }

上面这个函数又调用了下面这个函数。

  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<Object,Object> item: overlay.entrySet()) {
            updatingResource.put((String) item.getKey(), "Unknown");
          }
        }
      }
    }
    return properties;
  }

上面这个函数又调用了下面这个函数。

  private void loadResources(Properties properties,
                             ArrayList resources,
                             boolean quiet) {
    if(loadDefaults) {
      for (String resource : defaultResources) {
        loadResource(properties, resource, quiet);
      }
    
      //support the hadoop-site.xml as a deprecated case
      if(getResource("hadoop-site.xml")!=null) {
        loadResource(properties, "hadoop-site.xml", quiet);
      }
    }
    
    for (Object resource : resources) {
      loadResource(properties, resource, quiet);
    }
  }

上面这个函数又调用了下面这个函数。到现在才真正加载了配置文件。

 private void loadResource(Properties properties, Object name, boolean quiet) {

}

整个配置文件调用链如下:

getXXX()->get(String name)->getProps()->loadResource()-> loadResource()

2. 下面要着重介绍几个函数

loadResources()

当loadDefaults为true的情况下,会加载defaultResources包含的配置文件。但是无论loadDefaults是何值,都会加载resources包含的配置文件。而且按照先后顺序,resources包含的配置信息会覆盖defaultResources包含的配置信息

  private void loadResources(Properties properties,
                             ArrayList resources,
                             boolean quiet) {
    if(loadDefaults) {
      for (String resource : defaultResources) {
        loadResource(properties, resource, quiet);
      }
    
      //support the hadoop-site.xml as a deprecated case
      if(getResource("hadoop-site.xml")!=null) {
        loadResource(properties, "hadoop-site.xml", quiet);
      }
    }
    
    for (Object resource : resources) {
      loadResource(properties, resource, quiet);
    }
  }

配置修改

1.分析

配制的修改和配置的加载有相似之处。
当调用类似下面的函数的时候,开始修改配置文件

void setXXX(String name, float value){
	set(name,Float.toString(value));
}

显然,上面的函数调用了下面这个函数。根据下面这个函数可知,同时修改了Overlay和Props

  public void set(String name, String value) {
    getOverlay().setProperty(name, value);
    getProps().setProperty(name, value);
  }

现在又回到了getProps()。我们再来回顾一下这个函数。当properties不为null,直接返回properties。当properties为null.则重新加载默认的配置文件和用户添加的配置文件。同时如果overlay(前面已经说过,这里面放的是被修改的配置信息)不为空,说明有配置信息被修改过,也要重新加载overlay里的配置信息。并在updatingResource里记录那些信息被本进程(只是本进程,其他进程修改的不在此范围内)修改过。

  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<Object,Object> item: overlay.entrySet()) {
            updatingResource.put((String) item.getKey(), "Unknown");
          }
        }
      }
    }
    return properties;
  }

总结

当调用reloadConfiguration()函数的时候回将properties置为null,此后如果再调用进行set和get操作都要重新加载配置文件。而下面这些函数触发了reloadConfiguration()函数。

addResourceObject()
addDefaultResourc()
dumpConfiguration()
发布了85 篇原创文章 · 获赞 21 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_37275456/article/details/100591127