hadoop源码解析2 - conf包中Configuration.java解析

1 Hadoop Configuration简介     Hadoop没有使用java.util.Properties管理配置文件,也没有使用Apache Jakarta Commons Configuration管理配置文件,而是使用了一套独有的配置文件管理系统,并提供自己的API,即使用org.apache.hadoop.conf.Configuration处理配置信息。

    org.apache.hadoop.conf目录结构如下:

2 Hadoop配置文件的格式解析     Hadoop配置文件采用XML格式,下面是Hadoop配置文件的一个例子:

    <?xml version="1.0"?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
    <configuration>
      <property>
         <name>io.sort.factor</name>
         <value>10</value>
         <description>The number of streams to merge at once while sorting  
         files.  This determines the number of open file handles.</description>
      </property>
    <property>
         <name>dfs.name.dir</name>
         <value>${hadoop.tmp.dir}/dfs/name</value>
         <description>Determines where on the local filesystem the DFS name  
         nodeshould store the name table(fsimage).  ……</description>
      </property>
    <property>
         <name>dfs.web.ugi</name>
         <value>webuser,webgroup</value>
         <final>true</final>
         <description>The user account used by the web interface.  
         Syntax: USERNAME,GROUP1,GROUP2, ……</description>
      </property>
    </configuration>

    Hadoop配置文件的根元素是configuration,一般只包含子元素property。每一个property元素就是一个配置项,配置文件不支持分层或分级。每个配置项一般包括配置属性的名称name、值value和一个关于配置项的描述description;元素final和Java中的关键字final类似,意味着这个配置项是“固定不变的”。final一般不出现,但在合并资源的时候,可以防止配置项的值被覆盖。     在上面的示例文件中,配置项dfs.web.ugi的值是“webuser,webgroup”,它是一个final配置项;从description看,这个配置项配置了Hadoop Web界面的用户账号,包括用户名和用户组信息。这些信息可以通过Configuration类提供的方法访问。     在Configuration中,每个属性都是String类型的,但是值类型可能是以下多种类型,包括Java中的基本类型,如boolean(getBoolean)、int(getInt)、long(getLong)、float(getFloat),也可以是其他类型,如String(get)、java.io.File(getFile)、String数组(getStrings)等。以上面的配置文件为例,getInt("io.sort.factor")将返回整数10;而getStrings("dfs.web.ugi")返回一个字符串数组,该数组有两个元素,分别是webuser和webgroup。     合并资源指将多个配置文件合并,产生一个配置。如果有两个配置文件,也就是两个资源,如core-default.xml和core-site.xml,通过Configuration类的loadResources()方法,把它们合并成一个配置。代码如下:     Configurationconf = new Configuration();       conf.addResource("core-default.xml");       conf.addResource("core-site.xml");     如果这两个配置资源都包含了相同的配置项,而且前一个资源的配置项没有标记为final,那么,后面的配置将覆盖前面的配置。上面的例子中,core-site.xml中的配置将覆盖core-default.xml中的同名配置。如果在第一个资源(core-default.xml)中某配置项被标记为final,那么,在加载第二个资源的时候,会有警告提示。

3 直接运行Configuration.java则会调用默认配置文件部分结果如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configuration>
<property>
    <name>ipc.client.fallback-to-simple-auth-allowed</name>
    <value>false</value>
    <source>core-default.xml</source>
</property>
<property>
    <name>file.bytes-per-checksum</name>
    <value>512</value>
    <source>core-default.xml</source>
</property>
<property>
    <name>ipc.server.tcpnodelay</name>
    <value>false</value>
    <source>core-default.xml</source>
</property>
<property>
    <name>ftp.client-write-packet-size</name>
    <value>65536</value>
    <source>core-default.xml</source>
</property>
<property>
    <name>nfs3.mountd.port</name>
    <value>4272</value>
    <source>core-site.xml</source>
</property>
</configuration>

4 我们一般在wordcount程序中使用Configuration的set函数来添加或修改相关配置项,下面通过这种途径解析其具体实现方式

4.1 Configuration conf = new Configuration(true)的具体实现如下(见4.1.2):

    Configuration有3个构造函数:

    4.1.1 如果在新建Configuration对象时无参数,则系统默认调用该构造函数

    public Configuration() {
        this(true);
    }

    4.1.2 如果在新建Configuration对象时有boolean类型形参,则调用该构造函数

    /**
     * 1 新建一个Configuration类,如果loadDefaults=false,
     * 则新建的Configuration实例默认不会加载默认的配置文件
     */
    public Configuration(boolean loadDefaults) {
        System.out.println("Configuration(boolean loadDefaults)");
        this.loadDefaults = loadDefaults;// 选择是否加载默认配置文件,false为不加载,true加载
        System.out.println("loadDefaults: " + loadDefaults);
        updatingResource = new HashMap<String, String[]>();// 保存修改过的配置项
        synchronized (Configuration.class) {
            REGISTRY.put(this, null);
        }
    }

    4.1.3 如果在新建Configuration对象时有Configuration类型形参,则调用该构造函数

    /**
     * 
     * @param 调用其它Configuration对象的配置文件
     */
    @SuppressWarnings("unchecked")
    public Configuration(Configuration other) {
        this.resources = (ArrayList<Resource>) other.resources.clone();
        synchronized (other) {
            if (other.properties != null) {
                this.properties = (Properties) other.properties.clone();
            }

            if (other.overlay != null) {
                this.overlay = (Properties) other.overlay.clone();
            }

            this.updatingResource = new HashMap<String, String[]>(
                    other.updatingResource);
        }

        this.finalParameters = new HashSet<String>(other.finalParameters);
        synchronized (Configuration.class) {
            REGISTRY.put(this, null);
        }
        this.classLoader = other.classLoader;
        this.loadDefaults = other.loadDefaults;
        setQuietMode(other.getQuietMode());
    }

4.2 conf.set("fs.defaultFS", "file///");

    set函数有:

        public void set(String name, String value, String source)

        public void set(String name, String value)

        public synchronized void setIfUnset(String name, String value)

        public void setInt(String name, int value)

        public void setLong(String name, long value)

        public void setFloat(String name, float value)

        public void setDouble(String name, double value)

        public void setBoolean(String name, boolean value)

        public void setBooleanIfUnset(String name, boolean value)

        public <T extends Enum<T>> void setEnum(String name, T value)

        public void setTimeDuration(String name, long value, TimeUnit unit)

        public void setPattern(String name, Pattern pattern)

        public void setStrings(String name, String... values)

        public void setStrings(String name, String... values)

        public void setClass(String name, Class<?> theClass, Class<?> xface)

    其中,后面的set相关函数都是调用第一个set函数实现,下面就具体解析一下public void set(String name, String value, String source)

    /**
     * 
     * @Title        set
     * @Description  将参数name对应的value存入property中,如果该name在property中存在则覆盖,否则添加
     * @param
     * @return
     * @throws
     */
    public void set(String name, String value, String source) {
        System.out.println("set(name, value, source) start !");

        Preconditions.checkArgument(name != null, "Property name must not be null");
        Preconditions.checkArgument(value != null, "The value of property " + name + " must not be null");
        DeprecationContext deprecations = deprecationContext.get();//保存不在配置文件的key
        System.out.println("deprecations: "+deprecations);
        System.out.println("deprecations.getDeprecatedKeyMap().isEmpty(): "+deprecations.getDeprecatedKeyMap().isEmpty());
        if (deprecations.getDeprecatedKeyMap().isEmpty()) {
            getProps();
        }
        
        getOverlay().setProperty(name, value);
        getProps().setProperty(name, value);
        String newSource = (source == null ? "programatically" : source);

        System.out.println("newSource: " + newSource);
        if (!isDeprecated(name)) {//检测该name(key)项是否在配置文件中存在
            
            System.out.println("!isDeprecated(name): " + !isDeprecated(name));
            
            updatingResource.put(name, new String[] { newSource });//将该name(key)项参数添加进updatingResource中,说明该项已被修改
            String[] altNames = getAlternativeNames(name);//判断该name(key)是否在默认配置文件中存在,如果存在则将name存入altNames中
            
            /**
             * 如果name(key)则默认配置文件中存在,则将name对应value存入updatingResource
             */
            if (altNames != null) {
                for (String n : altNames) {
                    System.out.println("altNames: "+n);
                    if (!n.equals(name)) {
                        getOverlay().setProperty(n, value);
                        getProps().setProperty(n, value);
                        updatingResource.put(n, new String[] { newSource });
                    }
                }
            }
        } else {
            String[] names = handleDeprecation(deprecationContext.get(), name);
            String altSource = "because " + name + " is deprecated";
            for (String n : names) {
                
                System.out.println("names: "+names);
                
                getOverlay().setProperty(n, value);
                getProps().setProperty(n, value);
                updatingResource.put(n, new String[] { altSource });
            }
        }
    }

5 Configuration测试程序如下:

/**  
 * @Title        ConfigurationTest.java
 * @Package      org.apache.hadoop.conftest
 * @Description  TODO
 * @date         2014年9月11日 上午11:27:14
 * @version      V1.0
 */
package org.apache.hadoop.conftest;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;

public class ConfigurationTest {
    public static void main(String args[]){
        Configuration conf = new Configuration(true);
        Path hadoop_mapred = new Path("hadoop-2.3.0/etc/hadoop/mapred-site.xml");
        Path hadoop_yarn = new Path("hadoop-2.3.0/etc/hadoop/yarn-site.xml");
        conf.addResource(hadoop_mapred);
        conf.addResource(hadoop_yarn);
        conf.set("mapreduce.jobtracker.system.dir", "file:///data1");//this conf can change the same parameter in the mapred-site.xml when the paramter is used
        conf.setInt("test1", 10);//This parameter will be add to property due to it not in the properties
        conf.set("fs.defaultFS", "file///data");//This parameter will change the same parameter value in the properties
        System.out.println(conf.get("test1"));
        System.out.println(conf.get("mapreduce.jobtracker.system.dir"));
        System.out.println(conf.get("yarn.resourcemanager.admin.address"));
        System.out.println("ok");
    }
}

参考文件:http://f.dataguru.cn/thread-258563-1-1.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏不会写文章的程序员不是好厨师

日志那些事儿——Logback源码解析

在上篇文章日志漫谈中谈到,日志在监控报警、查错分析等方面有着非常重要的应用。Logback作为目前最火的日志系统,本文就简单分析一下logback日志打印的过程...

4722
来自专栏机器学习从入门到成神

在MyEclipse中使用Junit 的方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

1011
来自专栏软件工程师成长笔记

spring boot--Deferred方式实现异步调用,提高系统的吞吐量

在我们的实际生产中,常常会遇到下面的这种情况,某个请求非常耗时(大约5s返回),当大量的访问该请求的时候,再请求其他服务时,会造成没有连接使用的情况,造成这种现...

3522
来自专栏大内老A

ASP.NET MVC Controller激活系统详解:默认实现

Controller激活系统最终通过注册的ControllerFactory创建相应的Conroller对象,如果没有对ControllerFactory类型或...

2309
来自专栏Java帮帮-微信公众号-技术文章全总结

JSP简单入门(1)

JSP页面中可以包含模板元素、脚本元素、EL表达式、注释、指令、和行为元素(JSP标签)等内容。有三种类型的脚本元素:JSP脚本片断、JSP表达式和JSP声明,...

44711
来自专栏小尘哥的专栏

【springboot+easypoi】一行代码搞定简单的word导出

2864
来自专栏xingoo, 一个梦想做发明家的程序员

基于Dubbo的http自动测试工具分享

公司是采用微服务来做模块化的,各个模块之间采用dubbo通信。好处就不用提了,省略了之前模块间复杂的http访问。不过也遇到一些问题: PS: Githu...

4238
来自专栏lgp20151222

@Autowired的使用--Spring规范解释,推荐对构造函数进行注释

Spring Team recommends "Always use constructor based dependency injection in you...

1.9K3
来自专栏chenssy

哦,这就是java的优雅停机?(实现及原理)

其实优雅停机,就是在要关闭服务之前,不是立马全部关停,而是做好一些善后操作,比如:关闭线程、释放连接资源等。

1592
来自专栏weixuqin 的专栏

JSP 语法

脚本程序可以包含任意量的Java语句、变量、方法或表达式,只要它们在脚本语言中是有效的。(其中声明的变量为局部变量)

1262

扫码关注云+社区

领取腾讯云代金券