- Hadoop Configuration 类加载属性解析
- 1. 疑问
- 1.1. 结论
- 2. 从源码中一探究竟
- 2.1. `new Configuration()`时发生了什么
- 2.2. `configuration.get("fs.defaultFS")`时发生了什么
1. 疑问以下过程在3.2.2版本的源码上分析
当我们创建HDFS client时,最简单的做法如下:
Configuration configuration = new Configuration(); FileSystem fileSystem = FileSystem.get(configuration);
然后即可通过fileSystem对象来操作相应的API。
FileSystem实例从Configuration实例中获取HDFS相应配置,那么Configuration是如何获取HDFS的相关配置项呢?
当我们未手动将hadoop相关配置文件放置到classpath中时,直接执行如下代码,控制台打印file:///,get()时,从哪里获取默认配置值,发生了什么?
Configuration configuration = new Configuration();
String s = configuration.get("fs.defaultFS");
System.out.println(s); // 打印file:///
1.1. 结论
直接上结论。在创建Hadoop(HDFS、Yarn、MR)相应客户端时,想要正确加载所需环境属性配置,需要按以下操作:
- 将core-site.xml文件放置到classpath路径中(必选)。
默认情况下,classpath中的hadoop-common-3.2.2.jar中有core-default.xml文件,因此当未手动将core-site.xml文件放置到classpath中时,默认是从core-default.xml文件中加载默认属性,当把core-site.xml文件放置到classpath中,会覆盖core-default.xml中的默认属性值 - 请勿将hadoop-site.xml文件放置到classpath路径中。
否则在执行代码时,会得到DEPRECATED: hadoop-site.xml found in the classpath.相应的日志告警。 - 如果创建HDFS Client,将hdfs-site.xml文件放置到classpath路径中。
- 如果创建Yarn Client,将yarn-site.xml文件放置到classpath路径中
- 如果创建MR Client,将yarn-site.xml文件放置到classpath路径中
2. 从源码中一探究竟 2.1. new Configuration()时发生了什么org.apache.hadoop.hdfs.HdfsConfiguration、org.apache.hadoop.yarn.conf.YarnConfiguration、org.apache.hadoop.mapred.JobConf 都继承自 org.apache.hadoop.conf.Configuration类,
其中实例化org.apache.hadoop.hdfs.HdfsConfiguration时会将hdfs-default.xml和hdfs-site.xml文件添加到默认配置文件中。
实例化org.apache.hadoop.yarn.conf.YarnConfiguration时会将yarn-default.xml和yarn-site.xml文件添加到默认配置文件中。
实例化org.apache.hadoop.mapred.JobConf时会将mapred-default.xml、mapred-site.xml、yarn-default.xml和yarn-site.xml文件添加到默认配置文件中。
Configuration configuration = new Configuration();
当使用如上方式实例化configuration时,首先加载Configuration类中的static属性和代码块,
实例化static属性
主要依次实例化了如下属性
private static final WeakHashMapREGISTRY = new WeakHashMap (); private static final CopyOnWriteArrayList defaultResources = new CopyOnWriteArrayList (); private static DeprecationDelta[] defaultDeprecations = new DeprecationDelta[] { new DeprecationDelta("topology.script.file.name", CommonConfigurationKeys.NET_TOPOLOGY_script_FILE_NAME_KEY), new DeprecationDelta("topology.script.number.args", CommonConfigurationKeys.NET_TOPOLOGY_script_NUMBER_ARGS_KEY), new DeprecationDelta("hadoop.configured.node.mapping", CommonConfigurationKeys.NET_TOPOLOGY_CONFIGURED_NODE_MAPPING_KEY), new DeprecationDelta("topology.node.switch.mapping.impl", CommonConfigurationKeys.NET_TOPOLOGY_NODE_SWITCH_MAPPING_IMPL_KEY), new DeprecationDelta("dfs.df.interval", CommonConfigurationKeys.FS_DF_INTERVAL_KEY), new DeprecationDelta("fs.default.name", CommonConfigurationKeys.FS_DEFAULT_NAME_KEY), new DeprecationDelta("dfs.umaskmode", CommonConfigurationKeys.FS_PERMISSIONS_UMASK_KEY), new DeprecationDelta("dfs.nfs.exports.allowed.hosts", CommonConfigurationKeys.NFS_EXPORTS_ALLOWED_HOSTS_KEY) }; private static AtomicReference deprecationContext = new AtomicReference ( new DeprecationContext(null, defaultDeprecations));
执行static代码块
该静态代码块中,主要作用为使用org.apache.hadoop.conf.Configuration#addDefaultResource方法给上面实例化的defaultResources集合添加元素,将core-default.xm、core-site.xml和hadoop-site.xml(classpath存在的情况下)文件名称添加到集合中。
!!! note “”
从static代码块中即可看出,默认使用的属性配置文件为core-default.xml、core-site.xml和hadoop-site.xml。
在/org/apache/hadoop/hadoop-common/3.2.2/hadoop-common-3.2.2.jar中默认带有了core-default.xml配置文件。
static {
// Add default resources
// 将core-default.xml和core-site.xml文件名添加到上面实例化的defaultResources集合中
addDefaultResource("core-default.xml");
addDefaultResource("core-site.xml");
// print deprecation warning if hadoop-site.xml is found in classpath
// 如果在classpath中找到了hadoop-site.xml文件,则打印告警信息,并将hadoop-site.xml文件名添加到defaultResources集合中
ClassLoader cL = Thread.currentThread().getContextClassLoader();
if (cL == null) {
cL = Configuration.class.getClassLoader();
}
if (cL.getResource("hadoop-site.xml") != null) {
LOG.warn("DEPRECATED: hadoop-site.xml found in the classpath. " +
"Usage of hadoop-site.xml is deprecated. Instead use core-site.xml, "
+ "mapred-site.xml and hdfs-site.xml to override properties of " +
"core-default.xml, mapred-default.xml and hdfs-default.xml " +
"respectively");
addDefaultResource("hadoop-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();
}
}
}
}
调用构造方法完成Configuration的实例化
public Configuration() {
this(true);
}
public Configuration(boolean loadDefaults) {
this.loadDefaults = loadDefaults;
synchronized(Configuration.class) {
// 将实例化的对象放入到REGISTRY集合中
REGISTRY.put(this, null);
}
}
2.2. configuration.get("fs.defaultFS")时发生了什么
回到开头的问题,当我们未手动将hadoop相关配置文件放置到classpath中时,以下代码为什么打印file:///?
Configuration configuration = new Configuration();
String s = configuration.get("fs.defaultFS");
System.out.println(s); // 打印file:///
首先从上述实例化过程中创建的deprecationContext属性中进行弃用属性key和对应新属性key的替换。
然后调用org.apache.hadoop.conf.Configuration#loadProps方法从默认的配置文件中加载相应属性。然后在该方法中调用org.apache.hadoop.conf.Configuration#loadResources加载属性。
关键过程见代码中的注释。
protected synchronized Properties getProps() {
if (properties == null) {
// 将成员属性properties赋值为空,用于存放加载后的属性
properties = new Properties();
loadProps(properties, 0, true);
}
return properties;
}
private synchronized void loadProps(final Properties props,
final int startIdx, final boolean fullReload) {
if (props != null) {
// 第一次执行该方法时,backup为null
Map backup =
updatingResource != null
? new ConcurrentHashMap<>(updatingResource) : null;
// 从此处开始真正的从配置文件中加载属性
// 加载属性,初始时props为空,resources为空,startIdx为0,fullReload为true
loadResources(props, resources, startIdx, fullReload, quietmode);
// 初始时,overlay不为null,但是为空
if (overlay != null) {
props.putAll(overlay);
if (backup != null) {
for (Map.Entry 


