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 inthisfile. -->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.publicString get(String name) {02.returnsubstituteVars(getProps().getProperty(name));03.}04.privatesynchronizedProperties getProps() {05.if(properties ==null) {06.properties =newProperties();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.returnproperties;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.privatestaticPattern varPat = Pattern.compile("\\$\\{[^\\}\\$\u0020]+\\}");03.//最多做20次扩展04.privatestaticintMAX_SUBST =20;05./**06.* 进行属性扩展,可以扩展保存再Configuration对象中的键值对,而且还可以使用Java虚拟机的系统属性,07.* 在该方法中属性扩展优先使用系统属性08.* @param expr09.* @return10.*/11.privateString substituteVars(String expr) {12.if(expr ==null) {13.returnnull;14.}15.Matcher match = varPat.matcher("");16.String eval = expr;17.//循环,做多做MAX_SUBST次属性扩展18.for(ints=0; s<MAX_SUBST; s++) {19.match.reset(eval);20.if(!match.find()) {21.returneval;//什么都没有找到,返回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.returneval;// return literal ${var}: var is unbound40.}41.// 进行替换42.eval = eval.substring(0, match.start())+val+eval.substring(match.end());43.}44.45.thrownewIllegalStateException("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 =newConfiguration();按照Java初始化顺序,先初始化静态域(static 变量和代码块),再初始化非静态成员变量,最后执行构造方法,那么新建一个Configuration对象conf时,先执行Configuration类中的静态域(static 变量和代码块),再初始化非静态成员变量,最后执行Configuration()这个构造方法,所以新建Configuration对象涉及的代码如下:
01./**用来设置加载配置的模式,如果quitemode为true,则再加载解析配置文件的过程中,不输出日志信息,该变量只是一个方便开发人员调试的变量**/02.privatebooleanquietmode =true;03.04./**05.* List of configuration resources.<br/>06.* 保存了所有通过addRescource()方法添加Configuration对象的资源07.*/08.privateArrayList<Object> resources =newArrayList<Object>();09.10./**11.* List of configuration parameters marked <b>final</b>.<br/>12.* 用于保存再配置文件中已经被声明为final的键值对的键13.*/14.privateSet<String> finalParameters =newHashSet<String>();15./**是否加载默认资源,这些默认资源保存在defaultResources中**/16.privatebooleanloadDefaults =true;17.18./**19.* Configuration objects<br/>20.* 记录了系统中所有的Configuration对象,21.*/22.privatestaticfinalWeakHashMap<Configuration,Object> REGISTRY =23.newWeakHashMap<Configuration,Object>();24.25./**26.* List of default Resources. Resources are loaded in the order of the list27.* entries<br/>28.* 默认资源,通过方法addDefaultResource()可以添加系统默认资源29.*/30.privatestaticfinalCopyOnWriteArrayList<String> defaultResources =31.newCopyOnWriteArrayList<String>();32.33./**34.* The value reported as the setting resource when a key is set35.* by code rather than a file resource.36.*/37.staticfinalString UNKNOWN_RESOURCE ="Unknown";38.39./**40.* Stores the mapping of key to the resource which modifies or loads41.* the key most recently42.*/43.privateHashMap<String, String> updatingResource;44.45.static{46.//print deprecation warning if hadoop-site.xml is found in classpath47.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.privateProperties properties;63./**用于记录通过set()方式改变的配置项,而不是通过加载配置资源解析得到的变量**/64.privateProperties overlay;65.privateClassLoader classLoader;66.{67.classLoader = Thread.currentThread().getContextClassLoader();68.if(classLoader ==null) {69.classLoader = Configuration.class.getClassLoader();70.}71.}72.73./** A new configuration. */74.publicConfiguration() {75.this(true);76.}77.78./** A new configuration where the behavior of reading from the default79.* resources can be turned off.80.*81.* If the parameter {@code loadDefaults} is false, the new instance82.* will not load resources from the default files.83.* @param loadDefaults specifies whether to load from the default files84.*/85.publicConfiguration(booleanloadDefaults) {86.this.loadDefaults = loadDefaults;87.updatingResource =newHashMap<String, String>();88.synchronized(Configuration.class) {89.REGISTRY.put(this,null);90.}91.}92.//正则表达式对象,包含正则表达式\$\{[^\}\$\ ]+\},u0020是unicode中标识空格的十六进制93.privatestaticPattern varPat = Pattern.compile("\\$\\{[^\\}\\$\u0020]+\\}");94.//最多做20次扩展95.privatestaticintMAX_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.privatevoidloadResources(Properties properties,02.ArrayList resources,03.booleanquiet) {04.if(loadDefaults) {05.for(String resource : defaultResources) {06.loadResource(properties, resource, quiet);07.}08.09.//support the hadoop-site.xml as a deprecated case10.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的更多相关文章
- Hadoop源码分析之数据节点的握手,注册,上报数据块和心跳
转自:http://www.it165.net/admin/html/201402/2382.html 在上一篇文章Hadoop源码分析之DataNode的启动与停止中分析了DataNode节点的启动 ...
- 【MyBatis源码分析】Configuration加载(下篇)
元素设置 继续MyBatis的Configuration加载源码分析: private void parseConfiguration(XNode root) { try { Properties s ...
- 【MyBatis源码分析】Configuration加载(上篇)
config.xml解析为org.w3c.dom.Document 本文首先来简单看一下MyBatis中将config.xml解析为org.w3c.dom.Document的流程,代码为上文的这部分: ...
- Hadoop源码分析之FileSystem抽象文件系统
Hadopo提供了一个抽象的文件系统模型FileSystem,HDFS是其中的一个实现. FileSystem是Hadoop中所有文件系统的抽象父类,它定义了文件系统所具有的基本特征和基本操作. Fi ...
- HADOOP源码分析之RPC(1)
源码位于Hadoop-common ipc包下 abstract class Server 构造Server protected Server(String bindAddress, int port ...
- hadoop源码分析(2):Map-Reduce的过程解析
一.客户端 Map-Reduce的过程首先是由客户端提交一个任务开始的. 提交任务主要是通过JobClient.runJob(JobConf)静态函数实现的: public static Runnin ...
- Hadoop源码分析之产生InputSplit文件过程
用户提交 MapReduce 作业后,JobClient 会调用 InputFormat 的 getSplit方法 生成 InputSplit 的信息. 一个 MapReduce 任务 ...
- Hadoop 源码分析(二四)FSNamesystem
以下轮到FSNamesystem 出场了. FSNamesystem.java 一共同拥有4573 行.而整个namenode 文件夹下全部的Java 程序总共也仅仅有16876 行,把FSNames ...
- Hadoop源码分析(mapreduce.lib.partition/reduce/output)
Map的结果,会通过partition分发到Reducer上.Reducer做完Reduce操作后,通过OutputFormat,进行输出.以下我们就来分析參与这个过程的类. Mapper的结果, ...
随机推荐
- Unity3D Android播放视频
http://blog.csdn.net/awnuxcvbn/article/details/17719789 using UnityEngine; using System.Collections; ...
- Unix 网络编程 I/O 模型 第六章
前提,也是重点是, 当接收收据.或者读取数据时,分两步 1 等待数据准备好. 2 从内核拷贝数据到进程. 对于一个network IO 即 socket(这里我们以read举例),它会涉及到两个系统对 ...
- 开源爬虫Labin,Nutch,Neritrix介绍和对比
crawler 开发 语言 功能 单一 支持分布式 爬取 效率 镜像 保存 Nutch Java × √ 低 × Larbin C++ √ × 高 √ Heritrix Java √ × 中 √ ** ...
- 【微软100题】定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。 如把字符串abcdef左旋转2位得到字符串cdefab。请实现字符串左旋转的函数。
package test; /** * 定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部. 如把字符串abcdef左旋转2位得到字符串cdefab. 请实现字符串左旋转的函数. * ...
- 执行pig出错Unhandled internal error. Found interface jline.Terminal, but class was expected
执行pig时报例如以下错误 2015-07-14 10:41:12,869 [main] ERROR org.apache.pig.Main - ERROR 2998: Unhandled inter ...
- Android 四大组件(Activity、Service、BroadCastReceiver、ContentProvider)
转载于:http://blog.csdn.net/byxdaz/article/details/9708491 http://blog.csdn.net/q876266464/article/deta ...
- mysql数据结构优化,范式和反范式
1.范式,正常的建表,反范式,为了提高效率,适当的已空间换时间 2.垂直拆分,就是把经常用的.或者text大存储的字段单独拉出来存表 3.水平拆分,解决数据量大的问题,进行取莫的方式将数据放到相同的n ...
- HTML5学习笔记 Geolocation(地理定位)
HTML5 Geolocation(地理定位)用于定位用户的位置. 定位用户的位置 html5 Geolocation API用于获得用户的地理位置 鉴于该特性可能低侵犯用户的隐私,除非用户同意,否则 ...
- 第23章、OnFocuChangeListener焦点事件(从零开始学Android)
在Android App应用中,OnFocuChangeListener焦点事件是必不可少的,我们在上一章的基础上来学习一下如何实现. 基本知识点:OnFocuChangeListener事件 一 ...
- 在Quartus使用TCL脚本文件配制管脚 《本人亲测》
方法一:Import Assignments步骤1: 使用记事本或类似软件新建一个txt文件(或csv文件),按如下格式编写管脚分配内容(不同的开发版,其内容也不同,本文以我使用的DIY_DE2开发板 ...