前言
Configuration是hadoop中五大组件的公用类,所以放在了core下,org.apache.hadoop.conf.Configruration。这个类是作业的配置信息类,任何作用的配置信息必须通过Configuration传递,因为通过Configuration可以实现在多个mapper和多个reducer任务之间共享信息。hadoop作为Apache旗下hadoop系列最早出现的组件,该组件的核心类Configuration对后续出现的hbase,have,spark的配置都有一定的借鉴意义。
概述
Configuration类最重要的作用是传递配置信息,所以其重要的属性应该是成员变量而非成员函数。
- resources 资源列表,用来存储配置文件名
- loadDefaults bool值,用来存储是否读取默认配置。默认是true
- REGISTRY hashmap,作用未知
- defaultResources 资源列表 默认的配置
- storeResource bool值 是否备份用户设置的配置信息到overlay
- updatingResource hashmap 本进程修改过的配置信息
- properties 最终的配置信息
- overlay 存放用户设置的配置信息(不包括配置文件的配置信息)
类初始化
我们按着类加载顺序和类实例化顺序来分析
1. 静态变量和静态代码块
静态代码块在defaultResources里添加了两个资源名:
addDefaultResource("core-default.xml");
addDefaultResource("core-site.xml");
public static synchronized void addDefaultResource(String name) {
if(!defaultResources.contains(name)) {
defaultResources.add(name);
for(Configuration conf : REGISTRY.keySet()) {
if(conf.loadDefaults) {
conf.reloadConfiguration();
}
}
}
}
2.非静态变量和非静态代码块
这里只是初始化了类加载器,并没有加载属性
private ClassLoader classLoader;
{
classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = Configuration.class.getClassLoader();
}
}
3. 构造函数
Configruration类有四个构造函数。构造函数并没有加载任何配置信息。
构造函数的作用有:
初始化loadDefaults
初始化REGISTRY
初始化storeResource
tips:
构造函数
- 当一个对象被创建时,系统会为这个实例的变量进行默认初始化。如果想改变这种默认的初始化,就需要用构造器来实现。
- 如果java没有提供任何构造函数,则系统会为java提供一个无参的构造函数。这个函数的函数体为空。因此可以说:java类至少包含一个构造函数。
- 当自定义构造函数之后,默认构造函数就不可再使用。如果不重新定义参数为空的构造函数,则无法使用" 类名(空)"实例化对象。
类加载顺序
https://blog.csdn.net/weixin_37275456/article/details/100594486
配置加载
1. 分析
到目前为止尚未发现有任何加载配置的迹象。也就是说类初始化之后如果没有任何配置信息。是一个空非配置类。那什么时候加载配置文件的呢?
答:第一次从配置类里获取配置信息的时候。例如调用:
public int getInt(String name, int defaultValue)
public long getLong(String name, long defaultValue)
public int getInt(String name, int defaultValue)
。。。
上面这些函数都直接或者间接的调用了下面这个函数
public String get(String name) {
return substituteVars(getProps().getProperty(name));
}
上面这个函数又调用了下面这个函数。
private synchronized Properties getProps() {
if (properties == null) {
properties = new Properties();
// 第一次加载配置
loadResources(properties, resources, quietmode);
if (overlay!= null) {
properties.putAll(overlay);
if (storeResource) {
for (Map.Entry<Object,Object> item: overlay.entrySet()) {
updatingResource.put((String) item.getKey(), "Unknown");
}
}
}
}
return properties;
}
上面这个函数又调用了下面这个函数。
private void loadResources(Properties properties,
ArrayList resources,
boolean quiet) {
if(loadDefaults) {
for (String resource : defaultResources) {
loadResource(properties, resource, quiet);
}
//support the hadoop-site.xml as a deprecated case
if(getResource("hadoop-site.xml")!=null) {
loadResource(properties, "hadoop-site.xml", quiet);
}
}
for (Object resource : resources) {
loadResource(properties, resource, quiet);
}
}
上面这个函数又调用了下面这个函数。到现在才真正加载了配置文件。
private void loadResource(Properties properties, Object name, boolean quiet) {
}
整个配置文件调用链如下:
getXXX()->get(String name)->getProps()->loadResource()-> loadResource()
2. 下面要着重介绍几个函数
loadResources()
当loadDefaults为true的情况下,会加载defaultResources包含的配置文件。但是无论loadDefaults是何值,都会加载resources包含的配置文件。而且按照先后顺序,resources包含的配置信息会覆盖defaultResources包含的配置信息
private void loadResources(Properties properties,
ArrayList resources,
boolean quiet) {
if(loadDefaults) {
for (String resource : defaultResources) {
loadResource(properties, resource, quiet);
}
//support the hadoop-site.xml as a deprecated case
if(getResource("hadoop-site.xml")!=null) {
loadResource(properties, "hadoop-site.xml", quiet);
}
}
for (Object resource : resources) {
loadResource(properties, resource, quiet);
}
}
配置修改
1.分析
配制的修改和配置的加载有相似之处。
当调用类似下面的函数的时候,开始修改配置文件
void setXXX(String name, float value){
set(name,Float.toString(value));
}
显然,上面的函数调用了下面这个函数。根据下面这个函数可知,同时修改了Overlay和Props
public void set(String name, String value) {
getOverlay().setProperty(name, value);
getProps().setProperty(name, value);
}
现在又回到了getProps()。我们再来回顾一下这个函数。当properties不为null,直接返回properties。当properties为null.则重新加载默认的配置文件和用户添加的配置文件。同时如果overlay(前面已经说过,这里面放的是被修改的配置信息)不为空,说明有配置信息被修改过,也要重新加载overlay里的配置信息。并在updatingResource里记录那些信息被本进程(只是本进程,其他进程修改的不在此范围内)修改过。
private synchronized Properties getProps() {
if (properties == null) {
properties = new Properties();
// 第一次加载配置
loadResources(properties, resources, quietmode);
if (overlay!= null) {
properties.putAll(overlay);
if (storeResource) {
for (Map.Entry<Object,Object> item: overlay.entrySet()) {
updatingResource.put((String) item.getKey(), "Unknown");
}
}
}
}
return properties;
}
总结
当调用reloadConfiguration()函数的时候回将properties置为null,此后如果再调用进行set和get操作都要重新加载配置文件。而下面这些函数触发了reloadConfiguration()函数。
addResourceObject()
addDefaultResourc()
dumpConfiguration()