概述

最近这一段时间在看apache druid的源码,看的过程中遇到了使用java解析命令行参数的库:airline,因此花了点时间看了一下文档并跟着例子 学习了一下,并记录下来。简要的说明一下,airline是基于注释的java框架,用于在java中构建强大的git风格的CLI

详解

show me the code!我们还是从demo说起吧

quick start

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.github.rvesse.airline.SingleCommand;
import com.github.rvesse.airline.annotations.Arguments;
import com.github.rvesse.airline.annotations.Command;
import com.github.rvesse.airline.annotations.Option;

@Command(name = "getting-started", description = "We're just getting started")
public class GettingStarted {

@Option(name = { "-f", "--flag" }, description = "An option that requires no values")
private boolean flag = false;

@Arguments(description = "Additional arguments")
private List<String> args;

public static void main(String[] args) {
// 定义生成解析器
SingleCommand<GettingStarted> parser = SingleCommand.singleCommand(GettingStarted.class);
GettingStarted cmd = parser.parse(args);
// 解析阶段
cmd.run();
}

private void run() {
if (args != null)
System.out.println("Arguments were " + StringUtils.join(args, ","));
}
}

在读懂上面的例子之前,我们还需要介绍一下airline中涉及的术语,不然说起来真的很拗口。

  • Command Line Interface (CLI):CLI是一组命令的集合的入口,这些命令可以是以group形式组织的。举个简单的例子,我们经常使用的git就可以认为是一个cli,git下面可以有很多组命令:git remote、 git add等。
  • Command:command是被用户调用的一个工具,简单点来说就是被@Command注解的类,一个Command可以归属于多个组。
  • Command Group:group是command的集合,group本身也是可以包含其他group的。
  • Option:和我们在命令行中常见的option是一致的
  • Arguments:arguments在这里和Option其实很相似,不过两者其实都是Command接收参数的方式,用途不同(但是可以相互实现)!

介绍了上面的基本术语之后,我们再来看一下一个Command正常的使用流程。

  • 定义:定义阶段通常使用注解来完成,注解中涉及的概念如上,当然也可以使用builder硬编码的方式来实现,两者均可。我们上面使用的是注解来完成的。
  • 解析:在定义完成之后,我们需要创建和运行解析器,
  • 执行:这一步就可以解析从命令行传过来的参数了

上面的quick start中的解释可以告一段落了,不过总的来说上面还是态弱鸡了,真是的生产环境中一般不会这么使用,接下来我们来看一下高级用法(有点像git风格的)。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Cli(name = "basic", 
description = "Provides a basic example CLI",
defaultCommand = GettingStarted.class,
commands = { GettingStarted.class, Tool.class })
public class BasicCli {
public static void main(String[] args) {
// 解析cli
com.github.rvesse.airline.Cli<Runnable> cli = new com.github.rvesse.airline.Cli<>(BasicCli.class);
Runnable cmd = cli.parse(args);
// 运行
cmd.run();
}
}

在上面的代码中,我们看到,这里并不再是@Command来注解了,趣儿代之的是使用了@Cli注解,前面我们已经说过了Cli其实是一个命令行的入口, 我们通常可以在@Cli中指定一系列的参数:

  • name:该Cli的名称
  • description: 描述信息
  • defaultCommand: 默认的Command(如果用户没有指定要运行的command的话就会选用这个command)
  • commands:直属于Cli的command
  • group:直属于cli的group或者其他group的group,其中会携带commands信息

在完成了cli的定义之后,我们需要解析该Cli,并会根据命令行的参数来选择command,最后都通过之后就可以真正的运行了。

注意分组信息可以在@Cli上指定,也可以在@Command上指定,两者的作用是一致的,@Cli会更灵活一些。

小结

本次分析到此为止,后面如果有需要继续补充。 参考链接:https://rvesse.github.io/airline/