hadoop2.0对命令调用的重构

原创,转载请注明出处  白硕 [email protected]
http://baishuo491.iteye.com/blog/1916241

2.0以后,重构为为以Command为基础的一系列类  bstract public class Command extends Configured
最核心的是run函数,里面主要的行为就是处理各种选项,展开参数,并且处理每个参数(注释原话 The default behavior is to process options, * expand arguments, and then process each argument.)
run函数里最核心的代码:
LinkedList<String> args = new LinkedList<String>(Arrays.asList(argv));
      processOptions(args);
      processRawArguments(args);
后面两个都是虚函数,要由子类来实现,因为不同的子类,处理的方法不一样。这个方法的注释上,给了调用过程,还是很复杂的:

<pre>
   * run
   * |-> {@link #processOptions(LinkedList)}
   * \-> {@link #processRawArguments(LinkedList)}
   *      |-> {@link #expandArguments(LinkedList)} //这个和下面这个是在Command类里面实现的
   *      |   \-> {@link #expandArgument(String)}*
   *      \-> {@link #processArguments(LinkedList)}
   *          |-> {@link #processArgument(PathData)}*
   *          |   |-> {@link #processPathArgument(PathData)}
   *          |   \-> {@link #processPaths(PathData, PathData...)}
   *          |        \-> {@link #processPath(PathData)}*
   *          \-> {@link #processNonexistentPath(PathData)}
   * </pre>

 
看看Command 的一个子类FsCommand , abstract public class FsCommand extends Command
里面有一个静态函数,
public static void registerCommands(CommandFactory factory) {
    factory.registerCommands(CopyCommands.class);
    factory.registerCommands(Count.class);
    factory.registerCommands(Delete.class);
    factory.registerCommands(Display.class);
。。。。。。。
如果要新建command,要这里面注册,这样就可以作为静态数据装载到内存里

public class CommandFactory extends Configured implements Configurable

里面有一个classMap  和 一个objectMap
  private Map<String, Class<? extends Command>> classMap =
    new HashMap<String, Class<? extends Command>>();

  private Map<String, Command> objectMap =
    new HashMap<String, Command>();

下面看看 CommandFactory 的函数  registerCommands
public void registerCommands(Class<?> registrarClass) {
    try {
      registrarClass.getMethod(
          "registerCommands", CommandFactory.class
      ).invoke(null, this);
    } catch (Exception e) {
      throw new RuntimeException(StringUtils.stringifyException(e));
    }
  }
是registrarClass 调用自己的registerCommands命令

看一看CopyCommands 的registerCommands 命令,
  public static void registerCommands(CommandFactory factory) {
    factory.addClass(Merge.class, "-getmerge");
    factory.addClass(Cp.class, "-cp");
    factory.addClass(CopyFromLocal.class, "-copyFromLocal");
    factory.addClass(CopyToLocal.class, "-copyToLocal");
    factory.addClass(Get.class, "-get");
    factory.addClass(Put.class, "-put");
  }
原来CopyCommands 还有自己一系列的内部子类,都是静态的,在这里统一注册,如果要新建CopyCommands子类,就要在这里注册
CommandFactory 的addClass函数,可见是put到classMap里面了,名字和类调换了一下位置,字符串做主键
  public void addClass(Class<? extends Command> cmdClass, String ... names) {
    for (String name : names) classMap.put(name, cmdClass);
  }
另外一个map objectMap,只有在FsShell的init函数里,被插入了Help() 和Usage() 两个对象

  protected void init() throws IOException {
    getConf().setQuietMode(true);
    if (commandFactory == null) {
      commandFactory = new CommandFactory(getConf());//创建一个单例的factory
      commandFactory.addObject(new Help(), "-help");
      commandFactory.addObject(new Usage(), "-usage");
      registerCommands(commandFactory);//调用自己的registerCommands,其实是调用FsCommand的registerCommands,之前有提过。为了和DFSAdmin区分开
    }
  }

具体到每个命令的调用,因为都是从fshell 启动的,调用链如下:
FsShell.init() line: 83
FsShell.run(String[]) line: 241
ToolRunner.run(Configuration, Tool, String[]) line: 70
ToolRunner.run(Tool, String[]) line: 84
FsShell.main(String[]) line: 304
init之后,通过instance = commandFactory.getInstance(cmd);的到Class,cmd是解析出来的如-cat等字符串,去classMap里就可以get到对应的Class

之后,调用instance.run  执行我们最初讨论的 Command.run

猜你喜欢

转载自baishuo491.iteye.com/blog/1916241