关于java:Picocli快速构建Java命令行程序

82次阅读

共计 4857 个字符,预计需要花费 13 分钟才能阅读完成。

置信每个 Java 程序员都曾应用过 Scanner,因编写出一个命令行程序而兴奋不已。

命令行程序也颇为实用,然而,应用 Java 来编写一个功能强大的命令行程序却并不容易,次要有以下几方面的痛点:

  • 没有成熟的框架来封装 参数接管 参数提醒 以及 参数校验
  • 很难解决参数的 互斥 以及特定命令的互相 依赖关系
  • 无奈进行命令 主动补全
  • 因为 JVM 解释执行字节码,并且 JIT 无奈在 短时执行 中发挥作用,Java 命令行程序 启动迟缓
  • 集成 SpringBoot 及其它组件后,启动更加迟缓

上述这些问题都能够应用 Picocli 来解决

本文次要向大家介绍 Picocli,以及剖析它是如何解决上述的问题,并介绍应用其构建一个控制台程序的根本流程,具体的使用指南请至官网文档。

官网:https://picocli.info

根本介绍

Picocli 致力于以最简洁的形式来创立一个基于 JVM 的功能强大的命令行程序。

Picocli aims to be the easiest way to create rich command line applications that can run on and off the JVM. 

下图是利用 Picocli 构建命令行程序,输入 checksum -h 后打印出的帮忙文档:

疾速开始

定义一个命令有两种形式:

  1. 应用 成员属性 来接管命令行参数,实现 Callable 接口并覆写 call() 办法定义业务流程
  2. 应用 类办法 的参数来接管命令行参数,办法外部就是业务流程,集体举荐这种。

以下是两种定义方法:

实现 Callable 接口

// 定义 checksum 命令,以及命令的提示信息
@Command(name = "checksum", mixinStandardHelpOptions = true, version = "checksum 4.0",
         description = "Prints the checksum (MD5 by default) of a file to STDOUT.")
class CheckSum implements Callable<Integer> {@Parameters(index = "0", description = "The file whose checksum to calculate.")
    private File file;

    @Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...")
    private String algorithm = "MD5";

    @Override
    public Integer call() throws Exception { // your business logic goes here...
        byte[] fileContents = Files.readAllBytes(file.toPath());
        byte[] digest = MessageDigest.getInstance(algorithm).digest(fileContents);
        System.out.printf("%0" + (digest.length*2) + "x%n", new BigInteger(1, digest));
        return 0;
    }

    // this example implements Callable, so parsing, error handling and handling user
    // requests for usage help or version help can be done with one line of code.
    public static void main(String... args) {int exitCode = new CommandLine(new CheckSum()).execute(args);
        System.exit(exitCode);
    }
}

类办法

# 上述代码可简化为:@Command(name = "checksum", mixinStandardHelpOptions = true, version = "checksum 4.0",
        description = "Prints the checksum (MD5 by default) of a file to STDOUT.")
public int checkSum(@Parameters(index = "0", description = "The file whose checksum to calculate.") File file,
                    @Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...") String algorithm) throws Exception {byte[] fileContents = Files.readAllBytes(file.toPath());
    byte[] digest = MessageDigest.getInstance(algorithm).digest(fileContents);
    System.out.printf("%0" + (digest.length * 2) + "x%n", new BigInteger(1, digest));
    return 0;
}

如何解决痛点

置信你曾经对 Picocli 有了初步理解,上面就开始答复 Picocli 是如何解决文章结尾提出的痛点的。

@Option 与 @Parameter

不同点

  • @Option 是 选项参数,分为 参数名 参数内容,应用参数名来辨别不同参数
  • @Parameter 地位参数,应用 地位 来辨别不同参数
  • @Option 能够叠加
  • @Option 润饰的参数若为布尔类型,则能够不加省略参数内容

相同点

  • 都能够定义默认值
  • 都能够为可选参数,默认 @Option(required = false)@Parameter 默认是必填,但能够通过 arity 属性来控制参数个数,arity = "0..1" 示意参数为 0 – 1 个。
  • 都能够应用 interactive = true 开启交互模式输出,例如明码等敏感信息

arity的默认值以及应用办法:

详见:https://picocli.info/#_arity

丰盛的参数类型

如果咱们应用 Scanner 读取参数,咱们须要手动进行参数解析和类型转换,而 Picocli 提供了开箱即用的参数类型解析器,反对绝大部分的 Java 罕用类,能够提前对类型进行查看,并且简化了类型解析过程。

详见:https://picocli.info/#_built_…

参数校验

Picocli反对多种参数校验形式:

  • 内置的 required 和 arity 查看
  • 手动在业务中查看
  • JSR-380 BeanValidation 注解

BeanValidation注解在 Spring MVC 的参数校验中经常出现,同样 Picocli 也对其反对,如常见注解:@NotNull, @NotEmpty, @Min, @Max等,弱小而实用。

详见:https://picocli.info/#_valida…

@ArgGroup(参数组)

@ArgGroup 用来定义一组参数,通过 @ArgGroup(exclusive = ture/false, multiplicity = "...") 与 @Option(required=ture/false) 和 @Parameter(@arity = "...") 联合,能够实现以下性能:

  • 一组 互斥 命令
  • 一组参数用户必须 至多输出一个
  • 一组具备 依赖关系 的命令,即若未输出某一参数,就不能输出某些参数。
  • 复合参数,@ArgGroup 可嵌套

详见:https://picocli.info/#_argument_groups

SpringBoot 集成

Picocli能够轻松地与 SpringBoot 联合.

<dependency>
    <groupId>info.picocli</groupId>
    <artifactId>picocli-spring-boot-starter</artifactId>
    <version>${picocli.version}</version>
</dependency>
@SpringBootApplication
public class MySpringMailer implements CommandLineRunner, ExitCodeGenerator {

    private IFactory factory;        
    private MailCommand mailCommand; 
    private int exitCode;

    // 结构器注入
    MySpringMailer(IFactory factory, MailCommand mailCommand) {
        this.factory = factory;
        this.mailCommand = mailCommand;
    }

    @Override
    public void run(String... args) {
        // let picocli parse command line args and run the business logic
        exitCode = new CommandLine(mailCommand, factory).execute(args);
    }

    @Override
    public int getExitCode() {return exitCode;}

    public static void main(String[] args) {
        // let Spring instantiate and inject dependencies
        System.exit(SpringApplication.exit(SpringApplication.run(MySpringMailer.class, args)));
    }
}

详见:https://picocli.info/#_spring_boot_example

主动补全

Picocli 能够主动生成命令补全脚本,从而实现按下 <TAB> 键的时候,能够进行 补全提醒 主动补全

详见:https://picocli.info/#_tab_autocomplete

执行命令

应用 Picocli 构建的命令行程序的应用形式大抵分为两种:

  1. 应用 alias 命令来简化执行 java -jar
  2. 打包为可执行文件,退出环境变量

alias

alias mycommand='java -cp"/path/to/picocli-4.6.1.jar:/path/to/myapp.jar"org.myorg.MainClass'

GraalVM Native

GraalVM Native Image 使得开发者能够 AOT(ahead-of-time compile 提前) 编译 Java 代码为可执行文件,也就是一个 native image。

家喻户晓,以往启动一个 SpringBoot 程序,个别都会破费几十秒,这对命令行程序的使用者十分不敌对,因为每一次命令都须要很长的延时能力失去响应。

而通过 GraalVM Native Image 编译后的可执行文件 启动速度十分快,快到足够满足命令行程序所需的响应时延。

同时,咱们可能依靠 Spring Native 我的项目提供的依赖和 Maven 插件,来简化打包流程。

详见:

Picocli 文档:https://picocli.info/#_graalvm_native_image

Spring Native 文档:https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/

示例我的项目:https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/

结语

因为篇幅和工夫无限,本文只分享了 Picocli 的个性与应用形式,倡议读者查看官网文档以取得最新、最全的使用指南。
之后若有工夫或者大家有趣味,我会持续更新具体的应用形式。


感谢您浏览本文,您的关注与点赞是对我最大的反对!

关注我的公众号“语冰 Yubing”可接管最新推送,外面也有我分享的一些优质资源。

正文完
 0