zoukankan      html  css  js  c++  java
  • Hadoop源码分析之Configuration

    转自:http://www.it165.net/admin/html/201312/2178.html

      • org.apache.hadoop.conf.Configuration类是Hadoop所有功能的基础类,每一种功能执行之前都需要有先得到一个Configuration对象。Hadoop使用了XML文件作为配置文件,来保存运行时的配置信息,然后将配置加载到Configuration对象中,要使用配置信息时直接从Configuration对象中取。

        Hadoop配置文件

        将下载的Hadoop压缩包解压后,再文件夹中有一个conf文件夹,这里面有一些Hadoop启动时使用的配置文件,比如配置Hadoop为伪分布式后的core-site.xml文件为:

        01.<?xml version="1.0"?>
        02.<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
        03. 
        04.<!-- Put site-specific property overrides in this file. -->
        05. 
        06.<configuration>
        07.<property>
        08.<name>fs.default.name</name>
        09.<value>hdfs://localhost:9000</value>
        10.</property>
        11.<property>
        12.<name>hadoop.tmp.dir</name>
        13.<value>/home/gmy/hadoop/tmp</value>
        14.</property>
        15.</configuration>
        如上面的xml代码所示,Hadoop的XML配置文件的根节点是configuration,下一层的节点是property,每个property都代表一个配置项,由键值对组成,name节点表示该配置项的键,value节点表示值,除了name和value节点,property节点另一个重要的子节点是final,它表示这个键值对是不可覆盖的,是固定不变的,和Java中的final关键字类似。property节点还有个description子节点,是对该属性的描述,类似于Java的注释,在程序中不使用。

        property的保存

        在Configuration类中,有个java.util.Properties类型的成员变量properties,它保存了所有读取到的键值对配置项。调用Configuration.get()方法时,是从properties对象中取值,Configuration.get()的相关代码如下:

        01.public String get(String name) {
        02.return substituteVars(getProps().getProperty(name));
        03.}
        04.private synchronized Properties getProps() {
        05.if (properties == null) {
        06.properties = new Properties();
        07.loadResources(properties, resources, quietmode);
        08.if (overlay!= null) {
        09.properties.putAll(overlay);
        10.for (Map.Entry<Object,Object> item: overlay.entrySet()) {
        11.updatingResource.put((String) item.getKey(), UNKNOWN_RESOURCE);
        12.}
        13.}
        14.}
        15.return properties;
        16.}

        其中get()方法中调用的substituteVars()是进行属性扩展,下面会有这个方法的介绍。

        属性扩展

        再get()方法中调用方法substituteVars()是对配置的属性扩展,那么什么是属性扩展呢?举例说明如下,如果配置项dfs.name.dir值是${hadoop.tmp.dir}/dfs/name,而配置项hadoop.tmp.dir的值是/data, 那么${hadoop.tmp.dir}会使用hadoop.tmp.dir的值/data进行扩展,扩展后dfs.name.dir的值为/data/dfs/name。再Configuration类中,方法substituteVars()就是用来进行属性扩展的,代码如下:

        01.//正则表达式对象,包含正则表达式${[^}$ ]+},u0020是unicode中标识空格的十六进制
        02.private static Pattern varPat = Pattern.compile("\$\{[^\}\$u0020]+\}");
        03.//最多做20次扩展
        04.private static int MAX_SUBST = 20;
        05./**
        06.* 进行属性扩展,可以扩展保存再Configuration对象中的键值对,而且还可以使用Java虚拟机的系统属性,
        07.* 在该方法中属性扩展优先使用系统属性
        08.* @param expr
        09.* @return
        10.*/
        11.private String substituteVars(String expr) {
        12.if (expr == null) {
        13.return null;
        14.}
        15.Matcher match = varPat.matcher("");
        16.String eval = expr;
        17.//循环,做多做MAX_SUBST次属性扩展
        18.for(int s=0; s<MAX_SUBST; s++) {
        19.match.reset(eval);
        20.if (!match.find()) {
        21.return eval;//什么都没有找到,返回
        22.}
        23.String var = match.group();
        24.//获得属性扩展的键
        25.var = var.substring(2, var.length()-1);
        26.String val = null;
        27.try {
        28.//先查看系统属性中是否有var对应的值,保证优先使用系统属性
        29.val = System.getProperty(var);
        30.catch(SecurityException se) {
        31.LOG.warn("Unexpected SecurityException in Configuration", se);
        32.}
        33.//如果系统属性中没有,则查看Configuration保存再键值对中是否有var的键值对
        34.if (val == null) {
        35.val = getRaw(var);
        36.}
        37.if (val == null) {
        38.//没有找到的,则返回
        39.return eval; // return literal ${var}: var is unbound
        40.}
        41.// 进行替换
        42.eval = eval.substring(0, match.start())+val+eval.substring(match.end());
        43.}
        44. 
        45.throw new IllegalStateException("Variable substitution depth too large: "
        46.+ MAX_SUBST + " " + expr);
        47.}
        在Configuration类中,使用正则表达式${[^}$ ]+}来匹配表达式expr中的${}符号,正则表达式中的${是匹配expr中的前面部分${,}匹配expr中的后面部分},[^}$ ]表示匹配除了^、}和$这三个字符的所有字符,而表达式中的+表示其前面的[^}$ ]至少出现一次。在substituteVars()方法中先得到一个Matcher对象,然后循环MAX_SUBST次对expr中匹配正则表达式的属性进行值替换(如果存在)。可以看到优先匹配系统属性,其次是Configuration.properties中的键值对。

        延迟加载

        Configuration类采取了一种延迟加载的方式来加载XML配置文件中的键值对。使用语句

        1.Configuration conf = new Configuration();
        按照Java初始化顺序,先初始化静态域(static 变量和代码块),再初始化非静态成员变量,最后执行构造方法,那么新建一个Configuration对象conf时,先执行Configuration类中的静态域(static 变量和代码块),再初始化非静态成员变量,最后执行Configuration()这个构造方法,所以新建Configuration对象涉及的代码如下:
        01./**用来设置加载配置的模式,如果quitemode为true,则再加载解析配置文件的过程中,不输出日志信息,该变量只是一个方便开发人员调试的变量**/
        02.private boolean quietmode = true;
        03. 
        04./**
        05.* List of configuration resources.<br/>
        06.* 保存了所有通过addRescource()方法添加Configuration对象的资源
        07.*/
        08.private ArrayList<Object> resources = new ArrayList<Object>();
        09. 
        10./**
        11.* List of configuration parameters marked <b>final</b>.<br/>
        12.* 用于保存再配置文件中已经被声明为final的键值对的键
        13.*/
        14.private Set<String> finalParameters = new HashSet<String>();
        15./**是否加载默认资源,这些默认资源保存在defaultResources中**/
        16.private boolean loadDefaults = true;
        17. 
        18./**
        19.* Configuration objects<br/>
        20.* 记录了系统中所有的Configuration对象,
        21.*/
        22.private static final WeakHashMap<Configuration,Object> REGISTRY =
        23.new WeakHashMap<Configuration,Object>();
        24. 
        25./**
        26.* List of default Resources. Resources are loaded in the order of the list
        27.* entries<br/>
        28.* 默认资源,通过方法addDefaultResource()可以添加系统默认资源
        29.*/
        30.private static final CopyOnWriteArrayList<String> defaultResources =
        31.new CopyOnWriteArrayList<String>();
        32. 
        33./**
        34.* The value reported as the setting resource when a key is set
        35.* by code rather than a file resource.
        36.*/
        37.static final String UNKNOWN_RESOURCE = "Unknown";
        38. 
        39./**
        40.* Stores the mapping of key to the resource which modifies or loads
        41.* the key most recently
        42.*/
        43.private HashMap<String, String> updatingResource;
        44. 
        45.static{
        46.//print deprecation warning if hadoop-site.xml is found in classpath
        47.ClassLoader cL = Thread.currentThread().getContextClassLoader();
        48.if (cL == null) {
        49.cL = Configuration.class.getClassLoader();
        50.}
        51.if(cL.getResource("hadoop-site.xml")!=null) {
        52.LOG.warn("DEPRECATED: hadoop-site.xml found in the classpath. " +
        53."Usage of hadoop-site.xml is deprecated. Instead use core-site.xml, "
        54."mapred-site.xml and hdfs-site.xml to override properties of " +
        55."core-default.xml, mapred-default.xml and hdfs-default.xml " +
        56."respectively");
        57.}
        58.addDefaultResource("core-default.xml");
        59.addDefaultResource("core-site.xml");
        60.}
        61./**配置文件解析后的键值对**/
        62.private Properties properties;
        63./**用于记录通过set()方式改变的配置项,而不是通过加载配置资源解析得到的变量**/
        64.private Properties overlay;
        65.private ClassLoader classLoader;
        66.{
        67.classLoader = Thread.currentThread().getContextClassLoader();
        68.if (classLoader == null) {
        69.classLoader = Configuration.class.getClassLoader();
        70.}
        71.}
        72. 
        73./** A new configuration. */
        74.public Configuration() {
        75.this(true);
        76.}
        77. 
        78./** A new configuration where the behavior of reading from the default
        79.* resources can be turned off.
        80.*
        81.* If the parameter {@code loadDefaults} is false, the new instance
        82.* will not load resources from the default files.
        83.* @param loadDefaults specifies whether to load from the default files
        84.*/
        85.public Configuration(boolean loadDefaults) {
        86.this.loadDefaults = loadDefaults;
        87.updatingResource = new HashMap<String, String>();
        88.synchronized(Configuration.class) {
        89.REGISTRY.put(thisnull);
        90.}
        91.}
        92.//正则表达式对象,包含正则表达式${[^}$ ]+},u0020是unicode中标识空格的十六进制
        93.private static Pattern varPat = Pattern.compile("\$\{[^\}\$u0020]+\}");
        94.//最多做20次扩展
        95.private static int MAX_SUBST = 20;

        从上面的代码可以看出再新建Configuration对象时并没有读取XML文件中的属性(Property),而只是通过静态方法addDefaultResource()将core-default.xml和core-site.xml这两个XML文件名加入到Configuration.defaultResources静态成员变量中。这样就完成了一个Configuration对象的初始化。再这个过程中并没有从XML文件中读取Property属性的键值对,所以延迟到了需要使用的时候加载。

        加载键值对

        上面说过Configuration采用了延迟加载的方式来加载XML配置文件,那么在什么时候取读取XML文件将XML文件中的键值对加载到内存呢?在调用Configuration.get()方法的时候。上面的property的保存部分说道了使用Configuration.get()方法再properties中通过给定的键取其对应的值,在get()方法中调用了getProps()方法,getProps()方法先判断properties是否为空,如果为空,则调用loadResources()方法来加载XML文件中的键值对保存在properties成员变量中,loadResources()方法的代码如下:

        01.private void loadResources(Properties properties,
        02.ArrayList resources,
        03.boolean quiet) {
        04.if(loadDefaults) {
        05.for (String resource : defaultResources) {
        06.loadResource(properties, resource, quiet);
        07.}
        08. 
        09.//support the hadoop-site.xml as a deprecated case
        10.if(getResource("hadoop-site.xml")!=null) {
        11.loadResource(properties, "hadoop-site.xml", quiet);
        12.}
        13.}
        14. 
        15.for (Object resource : resources) {
        16.loadResource(properties, resource, quiet);
        17.}
        18.}
        loadResources先加载默认的资源(defaultResources中保存),再加载形参resources对应的资源。其中defaultResources表示通过方法addDefaultResource()可以添加系统默认资源,成员变量resources表示所有通过addRescource()方法添加Configuration对象的资源。在loadResource()方法中读取XML文件进行加载。loadResource()方法使用了DOM方式处理XML,逻辑比较简单,具体关于DOM加载XML的方式可以查阅其他资料。

        总结

        Configuration类在Hadoop的Common包中,它是所有Hadoop功能的基石,所以了解Hadoop首先应该知道Configuration类的作用与构造。上面介绍了Configuration的一些主要的变量与方法,可以为后面的其他源码分析打下坚实的基础。

        Reference

        《Hadoop技术内幕:深入解析Hadoop Common和HDFS架构设计与实现原理》

  • 相关阅读:
    Leetcode 238. Product of Array Except Self
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 290. Word Pattern
    Leetcode 205. Isomorphic Strings
    Leetcode 107. Binary Tree Level Order Traversal II
    Leetcode 102. Binary Tree Level Order Traversal
    三目运算符
    简单判断案例— 分支结构的应用
    用switch判断月份的练习
    java基本打印练习《我行我素购物系统》
  • 原文地址:https://www.cnblogs.com/cxzdy/p/5034778.html
Copyright © 2011-2022 走看看