转自: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架构设计与实现原理》

Hadoop源码分析之Configuration的更多相关文章

  1. Hadoop源码分析之数据节点的握手,注册,上报数据块和心跳

    转自:http://www.it165.net/admin/html/201402/2382.html 在上一篇文章Hadoop源码分析之DataNode的启动与停止中分析了DataNode节点的启动 ...

  2. 【MyBatis源码分析】Configuration加载(下篇)

    元素设置 继续MyBatis的Configuration加载源码分析: private void parseConfiguration(XNode root) { try { Properties s ...

  3. 【MyBatis源码分析】Configuration加载(上篇)

    config.xml解析为org.w3c.dom.Document 本文首先来简单看一下MyBatis中将config.xml解析为org.w3c.dom.Document的流程,代码为上文的这部分: ...

  4. Hadoop源码分析之FileSystem抽象文件系统

    Hadopo提供了一个抽象的文件系统模型FileSystem,HDFS是其中的一个实现. FileSystem是Hadoop中所有文件系统的抽象父类,它定义了文件系统所具有的基本特征和基本操作. Fi ...

  5. HADOOP源码分析之RPC(1)

    源码位于Hadoop-common ipc包下 abstract class Server 构造Server protected Server(String bindAddress, int port ...

  6. hadoop源码分析(2):Map-Reduce的过程解析

    一.客户端 Map-Reduce的过程首先是由客户端提交一个任务开始的. 提交任务主要是通过JobClient.runJob(JobConf)静态函数实现的: public static Runnin ...

  7. Hadoop源码分析之产生InputSplit文件过程

        用户提交 MapReduce 作业后,JobClient 会调用 InputFormat 的 getSplit方法 生成 InputSplit 的信息.     一个 MapReduce 任务 ...

  8. Hadoop 源码分析(二四)FSNamesystem

    以下轮到FSNamesystem 出场了. FSNamesystem.java 一共同拥有4573 行.而整个namenode 文件夹下全部的Java 程序总共也仅仅有16876 行,把FSNames ...

  9. Hadoop源码分析(mapreduce.lib.partition/reduce/output)

    Map的结果,会通过partition分发到Reducer上.Reducer做完Reduce操作后,通过OutputFormat,进行输出.以下我们就来分析參与这个过程的类.   Mapper的结果, ...

随机推荐

  1. 探寻不同版本号的SDK对iOS程序的影响

    PDF版本号:http://pan.baidu.com/s/1eQ8DVdo 结论: 同样的代码.使用不同版本号的SDK来编译.会影响MachO头中的值, 从而使程序表现出不同的外观. 代码: - ( ...

  2. nginx 设置错误的自己定义404页面跳转到500

    5年前写的站, 当时是在apache下写的error page, 换了nginx后, 404页面直接跳到了500 server内部错误. 仅仅须要在配置 try_files 的时候指定一下就能够了 我 ...

  3. ajax local.href不跳转的原因之一

    ajax local.href不跳转的原因之一 打开F12发现一直报 next.html is not a function…… 后来发现next少了(),看得我尴尬症都犯了

  4. mysql 流程函数 存储引擎 InnoDB简单特性

    建表及插入数据语句: mysql> create table salary(userid int,salary decimal(9,2)); Query OK, 0 rows affected ...

  5. ubuntu——主题更新,Ubuntu-tweak安装

    1.首先打开终端 2.在终端中输入sudo apt-add-repository ppa:tualatrix/ppa 回车后输入密码等一会,导入密钥 3.再输入sudo apt-get update ...

  6. .Net 两大利器Newtonsoft.NET和Dapper

    你可以使用ado.net返回的DataTable让Newtonsoft.NET来序列化成Json. 当然你可以使用Dapper返回的List让Newtonsoft.NET来序列化成JSON. 参考资料 ...

  7. MySQL-安全对调两个表名

    我们想要的是同时完成表名对调,如果是先后的对掉,用RENAME的话可能会导致有些数据写入失败,那怎么办? 其实也不难,从MySQL手册里就能找到方法,那就是:同时锁定2个表,不允许写入,然后对调表名. ...

  8. Python 字符串与数字拼接报错

    Python 不像 JS 或者 PHP 这种弱类型语言里在字符串连接时会自动转换类型,而是直接报错. 如: 上述是Python 字符串与数字拼接报错,解决办法是:使用bytes函数把int型转换为st ...

  9. PHP安全细节(转)

    一个常见的PHP安全细则 发布时间:2012-01-09 10:18:50   来源:51cto   评论:0 点击:9 次 [字号:大 中 小] PHP本身再老版本有一些问题,比如在 php4.3. ...

  10. centos7删除原docker 安装新docker-ce

    这里用阿里云的镜像源,速度会快很多: yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager -- ...