1、 hadoop配置文件分析
在文档(6)中分析了hadoop对配置文件中弃用key的处理,并分析在使用配置文件时调用的set方法,该方法会调用getProps方法获取配置文件,然后将数据设置到配置文件中。
getProps方法详情如下:
protected synchronized Properties getProps() {
if (properties == null) {
properties = new Properties();
Map backup =
new ConcurrentHashMap(updatingResource);
loadResources(properties, resources, quietmode);
if (overlay != null) {
properties.putAll(overlay);
for (Map.Entry
首先是第2行判断properties是否为空,若为空则执行if语句内的代码,从配置文件中加载数据;若不为空则直接返回。if语句内首先会初始化一个properties对象,然后将updatingResource中的数据备份到一个新的map中,然后执行loadResources方法加载配置文件,然后根据加载的结果判断overlay是否为空,若不为空则将overlay中的数据添加到properties中去,并更新updatingResource。
加载配置文件的loadResources方法如下:
private void loadResources(Properties properties,
ArrayList resources,
boolean quiet) {
if(loadDefaults) {
for (String resource : defaultResources) {
loadResource(properties, new Resource(resource, false), quiet);
}
//support the hadoop-site.xml as a deprecated case
if(getResource("hadoop-site.xml")!=null) {
loadResource(properties, new Resource("hadoop-site.xml", false), quiet);
}
}
for (int i = 0; i < resources.size(); i++) {
Resource ret = loadResource(properties, resources.get(i), quiet);
if (ret != null) {
resources.set(i, ret);
}
}
}
首先是第4行的if语句,语句的判断条件为参数loadDefaults。这个参数的默认值是true,在初始化的时候赋值修改,在之前的文档中提到了在hdfsConfiguration初始化的时候这个值为true。
if语句内部,首先是第5到7行,这里会先遍历defaultResources参数。这个参数在之前分析hdfsConfiguration的时候提到过,在这两个配置文件类中有一段静态代码块,会将hdfs-default.xml、hdfs-site.xml、core-default.xml和core-site.xml添加到defaultResources中。第6行会将上面几个文件作为参数传给loadResource方法加载文件内的内容。
然后是第9行到第12行,这里和上面的逻辑相同,只是文件换为了hadoop-site.xml。
最后是第15行到末尾,这里也是在加载文件,只是文件换成了传入的resources中的文件。
加载文件使用的loadResource方法如下:
private Resource loadResource(Properties properties, Resource wrapper, boolean quiet) {
String name = UNKNOWN_RESOURCE;
try {
Object resource = wrapper.getResource();
name = wrapper.getName();
documentBuilderFactory docBuilderFactory
= documentBuilderFactory.newInstance();
//ignore all comments inside the xml file
docBuilderFactory.setIgnoringComments(true);
//allow includes in the xml file
docBuilderFactory.setNamespaceAware(true);
boolean useXInclude = !wrapper.isParserRestricted();
try {
docBuilderFactory.setXIncludeAware(useXInclude);
} catch (UnsupportedOperationException e) {
LOG.error("Failed to set setXIncludeAware(" + useXInclude
+ ") for parser " + docBuilderFactory, e);
}
if (wrapper.isParserRestricted()) {
docBuilderFactory.setFeature(
"http://apache.org/xml/features/disallow-doctype-decl", true);
}
documentBuilder builder = docBuilderFactory.newdocumentBuilder();
document doc = null;
Element root = null;
boolean returnCachedProperties = false;
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;
} else if (resource instanceof Properties) {
overlay(properties, (Properties)resource);
} 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();
}
if (!"configuration".equals(root.getTagName()))
LOG.fatal("bad conf file: top-level element not ");
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, wrapper.isParserRestricted()), quiet);
continue;
}
if (!"property".equals(prop.getTagName())) {
if (wrapper.isParserRestricted()
&& XINCLUDE_NS_URI.equals(prop.getNamespaceURI())) {
throw new RuntimeException("Error parsing resource " + wrapper
+ ": XInclude is not supported for restricted resources");
}
LOG.warn("Unexpected tag in conf file " + wrapper
+ ": expected but found <" + prop.getTagName() + ">");
}
NodeList fields = prop.getChildNodes();
String attr = null;
String value = null;
boolean finalParameter = false;
linkedList source = new linkedList();
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()));
}
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()]));
}
}
}
if (returnCachedProperties) {
overlay(properties, toAddTo);
return new Resource(toAddTo, name, wrapper.isParserRestricted());
}
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);
}
}
这段代码很长,主要作用是从xml中读取配置文件到properties。首先是第2行到第28行,这里主要是负责创建读取xml需要的参数与临时对象,这里解析xml使用的DOM方式,它会将xml加载到内存中并解析成树型结构。
然后是第30行到第54行,这里会根据resource的具体类型来解析数据。
然后是第56行到第64行,这里在检查并获取root节点。
然后是第65行到第68行,这里会确认解析完成的数据具体会存储到什么地方,默认为传入方法的properties,但在解析某些来源的数据时,会将参数returnCachedProperties设置为true。这时数据会存入一个临时的properties中。
然后是第71行拿去root下的节点开始解析xml。
然后是第73行使用for循环开始遍历节点。以core-site.xml为例,其配置如下:
这里主要有三层,第一次是configuration,第二层是property,第三层是name和value。
然后是第78行,当节点是configuration的情况下,执行if语句内的内容,将节点内的内容封装成一个新的resource,然后递归调用loadresource方法。
然后是第83行到第91行,这里处理的是非property的情况,主要处理方式为抛出异常。这里主要针对的是configuration内的第二层节点,从上面的文档key看出这里的第二层全是property,若出现非property的情况,那么代表配置文件出错了,需要修改配置文件。
然后是第92行到133行,这里是在处理property内的值。简单来说就是读取property中所有标签的值,然后调用loadProperty方法将参数设置到properties中(对于弃用key,会拿到它的所有的替换名,并将替换名也设置到properties中)。
最后是第135行到139行,到这里整个方法便执行完成了。第139行最后返回的是null,这是因为这种情况下数据都存储在传入的properties中。
至此configuration的set方法便解析完了,接着继续解析configuration的get方法,get方法内容如下:
public String get(String name) {
String[] names = handleDeprecation(deprecationContext.get(), name);
String result = null;
for(String n : names) {
result = substituteVars(getProps().getProperty(n));
}
return result;
}
首先是第2行的handleDeprecation方法,这个方法在文档(6)中解析过,其主要作用是获取name的替代名称,然后是第4行遍历返回的替代名称,然后从properties中获取该参数的配置的值。



