hyperv 发表于 2018-10-31 12:56:25

Hadoop执行jar文件流程分析

  利用./bin/hadoop脚本执行jar文件是执行Hadoop自带测试包hadoop-test-version.jar和hadoop-example-version.jar的标准方法,当然用户开发的程序也需要用这种方法在hadoop中执行。本文以执行pi计算方法为例,详细分析Hadoop执行jar文件的流程。所用到的命令例子如下:
  ./bin/hadoopjar hadoop-examples-1.1.2.jar pi 100 100
  涉及到的原文件列表如下:
  ./bin/hadoop
  ./src/core/org/apache/hadoop/util/RunJar.java
  ./src/examples/org/apache/hadoop/examples/ExampleDriver.java
  ./src/core/org/apache/hadoop/util/ProgramDriver.java
  1. bin/hadoop脚本执行流程
  Hadoop的脚本文件.bin/hadoop是Hadoop最终要的脚本,是绝大多数hadoop命令的入口。通过分析该脚本源代码,可知它的执行流程主要如下:
  (1)、获得用户命令COMMAND,本例是jar。
  (2)、设置JAVA_HOME,JAVA_HEAP_SIZE等变量。
  (3)、搜索诸如./build/class等目录,设置类路径CLASSPATH。
  (4)、设置诸如HADOOP_LOG_DIR,HADOOP_LOGFILE等变量。
  (5)、根据COMMAND的内容,确定需要加载执行的类CLASS和java参数HADOOP_OPTS,
  如COMMAND为jar时,CLASS=org.apache.hadoop.util.RunJarl。
  (6)、设置库路径JAVA_LIBRARY_PATH,主要是加载本地库路径。
  (7)、根据前6步设置的变量和得到的类信息,调用java执行类(RunJar)。
  2. org.apache.hadoop.util.RunJar执行流程
  ./bin/hadoop调用java命令加载执行RunJar类后,执行流程到达RunJar类的main函数,其主要内容如下(为突出重点,源代码化简如下):
  publics taticvoid main(String[] args) throws Throwable {
  String fileName = args;
  Filefile = new File(fileName);
  JarFile jarFile = newJarFile(fileName);
  Manifest manifest = jarFile.getManifest();
  if (manifest != null){
  mainClassName = manifest.getMainAttributes().getValue("Main-Class");
  }
  mainClassName = mainClassName.replaceAll("/",".");
  FiletmpDir = new File(newConfiguration().get("hadoop.tmp.dir"));
  tmpDir.mkdirs();
  final File workDir = File.createTempFile("hadoop-unjar","",tmpDir);
  workDir.mkdirs();
        unJar(file,workDir);
  ArrayListclassPath = newArrayList();
  ClassLoaderloader =new URLClassLoader(classPath.toArray(newURL));
  Thread.currentThread().setContextClassLoader(loader);
  Class mainClass =>forName(mainClassName,true,loader);
  Methodmain = mainClass.getMethod("main",newClass[] {
  Array.newInstance(String.class,0).getClass()});
  String[]newArgs = Arrays.asList(args).subList(firstArg,args.length).toArray(newString);
  main.invoke(null,new Object[] { newArgs });
  }
  RunJar的main函数主要流程如下:
  (1)、根据用户命令行参数首先得到jar文件的文件名,本里为hadoop-examples-1.1.2.jar,然后通过文件清单Manifest得到jar的主类Main-Class,通过查看该jar文件的META-INFO/MANIFEST.MF得知,jar文件的主类为org/apache/hadoop/examples/ExampleDriver。
  (2)、准备运行环境,在配置的系统路径hadoop.tmp.dir下创建hadoop-unjar*目录,作为作业执行的工作目录;然后调用unjar方法把jar文件解压到该目录下,unjar方法比较简单,在此不作分析。
  (3)、利用java反射机制和主类类名ExampleDriver得到运行时类mainClass,进而得到类的main方法,最后准备命令行参数,调用main.invoke执行ExampleDriver的main方法。
  3. org.apache.hadoop.examples.ExampleDriver执行流程
  RunJar利用java反射机制执行ExampleDriver的main方法,该方法源代码如下:
  public static void main(String argv[]){
  ProgramDriver pgd = new ProgramDriver();
  pgd.addClass("wordcount",WordCount.class,
  "Amap/reduce program that counts the words in the input files.");
  ...
  pgd.driver(argv);
  }
  该方法主要定义一个Programriver变量pgd,然后添加各种example的类和描述信息,然后调用pgd.driver(argv)方法执行对应example的类。
  4. org/apache/hadoop/util/ProgramDriver分析
  该类有一个内部类ProgramDescription,用来描述一个example类的相关信息;成员变量main表示example类的main方法,description是该exmaple类的简单描述。该内部类的invoke方法使用java反射机制执行example类的main方法。
  ProgramDriver类的成员变量programs记录了当前example类的映射集合,成员方法addClass用以把新的example类添加到programs中。方法driver(argv)查中programs得到argv对应的ProgramDescription对象,然后调用该对象的invoke方法执行该example类的main方法。
  5. 总结
  Hadoop通过功能强大的./bin/hadoop脚本实现了其绝大多数命令行接口。本文主要分析了hadoop执行jar文件的流程:通过解析jar文件的到主类,利用java反射机制执行主类的main方法,进而执行相关example类。这些example类是典型的mapreduce作业,对这些作业的分析和hadoopmapred框架加载执行这些作业,将在以后的学习中逐步分析。
  wzw0114
  2013.07.23

页: [1]
查看完整版本: Hadoop执行jar文件流程分析