【Hadoop源码研究】之Configuration
来源:互联网 发布:李世民 知乎 胡人 编辑:程序博客网 时间:2024/04/27 18:38
Email:zhoubangtao@gmail.com
转载请注明出处: http://blog.csdn.net/zhoubangtao/article/details/25977561
1. 介绍
Congfiguration类位于hadoop-common工程下的org.apache.hadoop.conf包下,它是Hadoop系统的配置文件类,如core-default.xml, hdfs-site.xml都是有本类进行读取和配置的,它保存了整个Hadoop运行环境的上下文。研究本类对于了解Hadoop读取配置文件的方式,运行时动态改变配置很有帮助!
特别注意:本文基于Hadoop 2.4版本进行研究
2. 详解
2.1 Configuartion概述
Configuration类采用懒加载模式(Lazy-Load)加载配置文件,内部由一个Properties对象properties存储所有的配置信息,并由一个Set对象finalParameters存储所有的final属性名,当调用Congfiguration.getXXX()时,会检测properties成员变量是否为空,如果为空则发起加载动作,否则直接获取属性的值。此外Configuration类实现了Iterator接口,也就是说你可以直接通过foreach进行遍历。
Configuration配置文件中的property标签包含一下几种子标签:
- name:属性名
- value:属性值
- final:是否可覆盖
- source:属性的来源(记录属性来自那个Resource,这里存的就是Resource的name属性)
- description:属性的描述信息,这个值不在Configuration中存储,仅用于用户阅读,除此之外其他属性都会存储下来
2.1 Configuartion主要方法和内部类
1. Resource内部类
Resource内部类代表一个配置资源(如:core-site.xml),有一个资源名称和资源对象(可以是String,URL,Path,InputStream等)构成,Configuration类有两种Resource:一种为默认配置资源(如:core-default.xml,core-site.xml等,由CopyOnWriteArrayList静态对象defaultResources存储),一种为用户自定义配置资源(由有一个ArrayList对象resources存储)
/** * List of default Resources. Resources are loaded in the order of the list * entries */ private static final CopyOnWriteArrayList<String> defaultResources = new CopyOnWriteArrayList<String>(); /** * List of configuration resources. */ private ArrayList<Resource> resources = new ArrayList<Resource>();
2. reloadConfiguration方法
该方法并不会真正触发加载动作,只是把properties置空,源码如下:
public synchronized void reloadConfiguration() { properties = null; // trigger reload finalParameters.clear(); // clear site-limits }
3. addResourceObject
该方法是添加用户配置资源的私有方法,它是通过一系列addResource重载方法向外提供服务,addResource根据资源对象的类型(String,URL,Path,InputStream等)定义了若干种重载方法,源码如下:
public void addResource(Configuration conf) { addResourceObject(new Resource(conf.getProps())); } private synchronized void addResourceObject(Resource resource) { resources.add(resource); // add to resources reloadConfiguration(); // 每添加一次资源都会置空一次properties }4. addDefaultResource
该方法是添加默认配置资源的public static方法,一般在静态代码块调用,代码如下:
/** * Add a default resource. Resources are loaded in the order of the resources * added. * @param name file name. File should be present in the classpath. */ public static synchronized void addDefaultResource(String name) { if(!defaultResources.contains(name)) { defaultResources.add(name); for(Configuration conf : REGISTRY.keySet()) { if(conf.loadDefaults) { conf.reloadConfiguration(); } } } }5. substituteVars私有方法
该方法是使用系统变量替换某一配置value中的${var}变量,如${user.name}会被替换成系统用户名
6. getProps方法
该方法是触发加载的最终方法
protected synchronized Properties getProps() { if (properties == null) {//如果properties为null,则加载配置 properties = new Properties(); HashMap<String, String[]> backup = new HashMap<String, String[]>(updatingResource); loadResources(properties, resources, quietmode); if (overlay!= null) { properties.putAll(overlay); for (Map.Entry<Object,Object> item: overlay.entrySet()) { String key = (String)item.getKey(); updatingResource.put(key, backup.get(key)); } } } return properties; }
7. get方法
该方法是Configuration类中最重要的取值方法,这里
public String get(String name) { String[] names = handleDeprecation(deprecationContext.get(), name); String result = null; for(String n : names) { result = substituteVars(getProps().getProperty(n));//这里调用了getProps,并且用substituteVars替换了变量 } return result; }
8. loadResource和loadResources私有方法
这两个方法都是私有方法,也就是说Configuration类一定是懒加载的,只有在get属性的时候才会加载配置,loadResource是加载单个Resource,由loadResources调用实现多个Resource加载
loadResource方法比较复杂,主要实现资源对象类型检测,并最终转化为xml的root元素进行解析(除资源类型为Properties外,它会直接覆盖目标propertis中然后方法推出,所以这里可能将final的值也给覆盖了,不过不用担心,在对外暴露的众多addResource重载方法中,并没有一个是添加Properties这种类型资源的,这个只是Configuration内部将InputStream这种资源类型转换成了Properties资源类型后使用的),
private Resource loadResource(Properties properties, Resource wrapper, boolean quiet) { String name = UNKNOWN_RESOURCE; try { Object resource = wrapper.getResource(); name = wrapper.getName(); //构建DocumentBuilder 略 Document doc = null; Element root = null; boolean returnCachedProperties = false;//是否转化为Properties资源类型 if (resource instanceof URL) { // an URL resource doc = parse(builder, (URL)resource); } else if (resource instanceof String) { // a CLASSPATH resource URL url = getResource((String)resource); doc = parse(builder, url); } else if (resource instanceof Path) { // a file resource // Can't use FileSystem API or we get an infinite loop // since FileSystem uses Configuration API. Use java.io.File instead. File file = new File(((Path)resource).toUri().getPath()) .getAbsoluteFile(); if (file.exists()) { if (!quiet) { LOG.debug("parsing File " + file); } doc = parse(builder, new BufferedInputStream( new FileInputStream(file)), ((Path)resource).toString()); } } else if (resource instanceof InputStream) { doc = parse(builder, (InputStream) resource, null); returnCachedProperties = true;//将InputStream类型转化为Properties类型 } else if (resource instanceof Properties) { overlay(properties, (Properties)resource); // 若为Properties类型,则直接覆盖,这里会导致root和doc都为null,后边就会退出 } else if (resource instanceof Element) { root = (Element)resource; } if (root == null) { if (doc == null) { if (quiet) { return null; } throw new RuntimeException(resource + " not found"); } root = doc.getDocumentElement(); } Properties toAddTo = properties; if(returnCachedProperties) { toAddTo = new Properties();//看到了吧,转化为Properties了 } if (!"configuration".equals(root.getTagName())) LOG.fatal("bad conf file: top-level element not <configuration>"); NodeList props = root.getChildNodes(); DeprecationContext deprecations = deprecationContext.get(); for (int i = 0; i < props.getLength(); i++) { Node propNode = props.item(i); if (!(propNode instanceof Element)) continue; Element prop = (Element)propNode; if ("configuration".equals(prop.getTagName())) { loadResource(toAddTo, new Resource(prop, name), quiet); continue; } if (!"property".equals(prop.getTagName())) LOG.warn("bad conf file: element not <property>"); NodeList fields = prop.getChildNodes(); String attr = null; String value = null; boolean finalParameter = false; LinkedList<String> source = new LinkedList<String>(); for (int j = 0; j < fields.getLength(); j++) { Node fieldNode = fields.item(j); if (!(fieldNode instanceof Element)) continue; Element field = (Element)fieldNode; if ("name".equals(field.getTagName()) && field.hasChildNodes()) attr = StringInterner.weakIntern( ((Text)field.getFirstChild()).getData().trim()); if ("value".equals(field.getTagName()) && field.hasChildNodes()) value = StringInterner.weakIntern( ((Text)field.getFirstChild()).getData()); if ("final".equals(field.getTagName()) && field.hasChildNodes()) finalParameter = "true".equals(((Text)field.getFirstChild()).getData()); if ("source".equals(field.getTagName()) && field.hasChildNodes()) source.add(StringInterner.weakIntern( ((Text)field.getFirstChild()).getData()));//把property属性中的source属性加入source中 } source.add(name);//这里又加了一个资源的名字,看函数开始部分 // Ignore this parameter if it has already been marked as 'final' if (attr != null) { if (deprecations.getDeprecatedKeyMap().containsKey(attr)) { DeprecatedKeyInfo keyInfo = deprecations.getDeprecatedKeyMap().get(attr); keyInfo.clearAccessed(); for (String key:keyInfo.newKeys) { // update new keys with deprecated key's value loadProperty(toAddTo, name, key, value, finalParameter, source.toArray(new String[source.size()])); } } else { loadProperty(toAddTo, name, attr, value, finalParameter, source.toArray(new String[source.size()]));//调用函数加载一个具体的property } } } if (returnCachedProperties) { overlay(properties, toAddTo); return new Resource(toAddTo, name); } return null; } catch (IOException e) { LOG.fatal("error parsing conf " + name, e); throw new RuntimeException(e); } catch (DOMException e) { LOG.fatal("error parsing conf " + name, e); throw new RuntimeException(e); } catch (SAXException e) { LOG.fatal("error parsing conf " + name, e); throw new RuntimeException(e); } catch (ParserConfigurationException e) { LOG.fatal("error parsing conf " + name , e); throw new RuntimeException(e); } }loadResources方法根据资源列表依次加载,并将loadResource返回的Resource发到资源列表的对应位置
private void loadResources(Properties properties, ArrayList<Resource> resources, boolean quiet) { if(loadDefaults) { for (String resource : defaultResources) {//加载默认资源 loadResource(properties, new Resource(resource), quiet); } //support the hadoop-site.xml as a deprecated case if(getResource("hadoop-site.xml")!=null) { loadResource(properties, new Resource("hadoop-site.xml"), quiet); } } for (int i = 0; i < resources.size(); i++) {//加载用户自定义资源 Resource ret = loadResource(properties, resources.get(i), quiet); if (ret != null) { resources.set(i, ret);//资源列表被改变了,原来的InputStream资源类型变成了Properties类型 } } }
9. loadProperty私有方法
用来添加一个property到指定的Properties中,并标记该property的来源到updatingResource中,如果是final的,还会将其属性名加到finalParameters中,源码如下:
private void loadProperty(Properties properties, String name, String attr, String value, boolean finalParameter, String[] source) { if (value != null) { if (!finalParameters.contains(attr)) { properties.setProperty(attr, value); updatingResource.put(attr, source); } else if (!value.equals(properties.getProperty(attr))) {//如果为final的,则不允许覆盖 LOG.warn(name+":an attempt to override final parameter: "+attr +"; Ignoring."); } } if (finalParameter) { finalParameters.add(attr); } }
参数说明:
properties:存放property
name:属性来源的Resource的name属性
attr:属性名
value:属性值
finalParameter:是否为final
source:属性的所有来源(包括该属性中配置的source值和属性所在的Resource的name属性)
10. 其他的get和set方法就不用说了,很简单无非是类型转换而已
2.3 Configuartion家族
1.位于org.apache.hadoop.conf下的Configuration类加载了默认配置文件core-default.xml和core-site.xml(hadoop-site.xml已经废弃),并没有加载HDFS的配置文件,也就是说,如果你new了Configuration则只能获取core的配置,那么使用HDFS API(如FileSystem)编程时怎么办呢?
实际上,在Hadoop 2.4中各个组件(Yarn,MR,HDFS等)都继承了Configuration从而加载了自己的配置文件,子类如下:
HdfsConfiguration:加载hdfs-default.xml和hdfs-site.xml
YarnConfiguration:加载yarn-default.xml和yarn-site.xml
JobConf:加载yarn-default.xml,yarn-site.xml,mapred-default.xml和mapred-site.xml
另外还有FairSchedulerConfiguration和CapacitySchedulerConfiguration
所以一定要注意了,如果使用HDFS的FileSystem应该像这样:
Configuration conf = new HdfsConfiguration();//new 一个HdfsConfiguration FileSystem fs = null; try { fs = FileSystem.get(URI.create("hdfs://ns1:8009"), conf); fs.listFiles(new Path("/"), false); } catch (IOException e) { e.printStackTrace(); }
3. 总结
本文阐述了Configuration的原理和一些主要方法的实现,最后指使用方法。
4. 参考资料
- http://hadoop.apache.org/
Email:zhoubangtao@gmail.com
转载请注明出处: http://blog.csdn.net/zhoubangtao/article/details/25977561
- 【Hadoop源码研究】之Configuration
- Hadoop深入研究之Configuration
- Spring源码研究之@Configuration
- hadoop源码之Configuration解析
- Hadoop源码分析之Configuration
- Hadoop源码分析之Configuration
- Hadoop源码之Configuration类
- Hadoop源码分析 之Configuration配置
- hadoop-common源码分析之-Configuration
- (一)hadoop源码学习之Configuration
- (二)hadoop源码学习之Configuration
- Hadoop Configuration 源码详解
- hadoop之Configuration.java
- Hadoop DFS源码研究之---Hadoop RPC机制
- hadoop源码研究(2)
- myBatis源码之Configuration
- hadoop源码解读——configuration
- Hadoop 2.6.0 Configuration源码分析
- rest
- MySQL数据库字符编码设置
- 百人二八杠(控制+机器人)源码下载
- [QuickSettings] How to add new toggles to 4.2 Android
- 命令行参数
- 【Hadoop源码研究】之Configuration
- iOS:苹果企业证书通过网页分发安装app
- java多态
- ThinkPHP处理海量数据分表机制详细代码
- 判断为iPhone 还是iPad?
- 设计模式【1】:原型模式【创建对象】
- Java集合详解
- 三星矫情,重温Galaxy S5发布会收买人心
- Oracle 网络问题错误日志典型格式