hdfs client分析:hdfs dfs -ls

shell脚本分析

实例命令:hdfs dfs -ls
对应脚本文件:bin/hdfs
对应具体脚本内容:

COMMAND=$1
shift
elif [ "$COMMAND" = "dfs" ] ; then
  CLASS=org.apache.hadoop.fs.FsShell

最终执行的命令:

exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS $CLASS "$@"
//其中,CLASS=org.apache.hadoop.fs.FsShell,$@=-ls

FsShell实现分析

当然是先看入口main

public static void main(String argv[]) throws Exception {
   
    //new FsShell()
    FsShell shell = newShellInstance();
    //加载core-default.xml,core-site.xml
    Configuration conf = new Configuration();
    //不开启安静模式(安静模式下错误和提示信息不会被打印)
    conf.setQuietMode(false);
    shell.setConf(conf);
    int res;
    try {
   
      //ToolRunner就是一个工具类,用于执行实现了接口`Tool`的类,FsShell是Tool的实现类
      res = ToolRunner.run(shell, argv);
    } finally {
   
      shell.close();
    }
    System.exit(res);
  }

ToolRunner类结合GenericOptionsParser类来解析命令行参数,
在运行上述ToolRunner.run(shell, argv)代码之后,经过一番解释之后,最后真正执行的仍然是类FsShell的run方法,而且对其参数进行了解析,run方法如下:

@Override
  public int run(String argv[]) throws Exception {
   
    // 初始化FsShll,包括注册命令类
    init();

    int exitCode = -1;
    if (argv.length < 1) {
   
      printUsage(System.err); //打印使用方法
    } else {
   
      String cmd = argv[0];//取到第一个参数,即 ls
      Command instance = null;
      try {
   
        instance = commandFactory.getInstance(cmd);  //实例化Command,即new Ls()
        if (instance == null) {
   
          throw new UnknownCommandException();
        }
        //调用LS的父类Command.run
        exitCode = instance.run(Arrays.copyOfRange(argv, 1, argv.length));
      } catch (IllegalArgumentException e) {
   
        displayError(cmd, e.getLocalizedMessage());
        if (instance != null) {
   
          printInstanceUsage(System.err, instance);
        }
      } catch (Exception e) {
   
        // instance.run catches IOE, so something is REALLY wrong if here
        LOG.debug("Error", e);
        displayError(cmd, "Fatal internal error");
        e.printStackTrace(System.err);
      }
    }
    return exitCode;
  }

(1)重点分析一:init()如下:

protected void init() throws IOException {
   
    getConf().setQuietMode(true); //开启安静模式
    if (commandFactory == null) {
   
      //实例话CommandFactory
      commandFactory = new CommandFactory(getConf()); 
      //为commandFactory注册命令-对象:help,usage (实例化了commandClass,放入commandFactory的objectMap中)
      commandFactory.addObject(new Help(), "-help");
      commandFactory.addObject(new Usage(), "-usage");
      // 注册命令-class,调用registerCommands方法(未实例化commandClass,延迟实例化,在真正使用的时候在通过反射进行实例化,放入commandFactory的classMap中)
      registerCommands(commandFactory);
    }
  }
protected void registerCommands(CommandFactory factory) {
   
    // TODO: DFSAdmin subclasses FsShell so need to protect the command
    // registration.  This class should morph into a base class for
    // commands, and then this method can be abstract
    if (this.getClass().equals(FsShell.class)) {
   
      // 调用CommandFactory类的registerCommands方法
      // 注意,这里传的参数是类FsCommand
      factory.registerCommands(FsCommand.class);
    }
  }

CommandFactory类的registerCommands方法如下:

public void registerCommands(Class<?> registrarClass) {
    try {
      // 这里触发的是类FsCommand的registerCommands方法
      registrarClass.getMethod(
          "registerCommands", CommandFactory.class
      ).invoke(null, this);
    } catch (Exception e) {
      throw new RuntimeException(StringUtils.stringifyException(e));
    }
  }

接下来,看看类CommandFactory的registerCommands方法,代码如下:

public static void registerCommands(CommandFactory factory) {
   
    factory.registerCommands(AclCommands.class);
    factory.registerCommands(CopyCommands.class);
    factory.registerCommands(Count.class);
    factory.registerCommands(Delete.class);
    factory.registerCommands(Display.class);
    factory.registerCommands(Find.class);
    factory.registerCommands(FsShellPermissions.class);
    factory.registerCommands(FsUsage.class);
    factory.registerCommands(Ls.class);
    factory.registerCommands(Mkdir.class);
    factory.registerCommands(MoveCommands.class);
    factory.registerCommands(SetReplication.class);
    factory.registerCommands(Stat.class);
    factory.registerCommands(Tail.class);
    factory.registerCommands(Test.class);
    factory.registerCommands(Touch.class);
    factory.registerCommands(Truncate.class);
    factory.registerCommands(SnapshotCommands.class);
    factory.registerCommands(XAttrCommands.class);
  }

我们再来看看Ls类

class Ls extends FsCommand {
   
  public static void registerCommands(CommandFactory factory) {
   
    factory.addClass(Ls.class, "-ls");
    factory.addClass(Lsr.class, "-lsr");
  }

(2)重点分析二:instance.run
调用父类Command的run方法:

* run
   * |-> {@link #processOptions(LinkedList)}
   * \-> {@link #processRawArguments(LinkedList)}
   *      |-> {@link #expandArguments(LinkedList)}
   *      |   \-> {@link #expandArgument(String)}*
   *      \-> {@link #processArguments(LinkedList)}
   *          |-> {@link #processArgument(PathData)}*
   *          |   |-> {@link #processPathArgument(PathData)}
   *          |   \-> {@link #processPaths(PathData, PathData...)}
   *          |        \-> {@link #processPath(PathData)}*
   *          \-> {@link #processNonexistentPath(PathData)}
public int run(String...argv) {
   
      //将String..
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值