相信每个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";@Overridepublic 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_in_types

参数校验

Picocli支持多种参数校验方式:

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

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

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

@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;}@Overridepublic void run(String... args) {// let picocli parse command line args and run the business logicexitCode = new CommandLine(mailCommand, factory).execute(args);}@Overridepublic int getExitCode() {return exitCode;}public static void main(String[] args) {// let Spring instantiate and inject dependenciesSystem.exit(SpringApplication.exit(SpringApplication.run(MySpringMailer.class, args)));}
}

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

自动补全

Picocli可以自动生成命令补全脚本,从而实现按下键的时候,可以进行补全提示自动补全

详见: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”可接收最新推送,里面也有我分享的一些优质资源。

Picocli-快速构建Java命令行程序相关推荐

  1. Java命令行程序构建工具airlift使用

    package com.ilucky.airlift;import java.util.Arrays;import io.airlift.airline.Cli; import io.airlift. ...

  2. Java命令行程序构建工具airlift使用之分组(group)

    闲话少说,直接上代码: package com.ilucky.druid.airlift.test2;import java.util.Arrays;import io.airlift.airline ...

  3. java 打印命令_Java 普通命令行程序main关掉 DEBUG 打印

    最近在写一个简单的java命令行程序,执行代码时,代码窗口出现了烦人的debug日志. 分析了一下,出现这种问题的原因是因为,maven项目的依赖包中传递依赖了一些日志框架,导致会出现日志内容的打印. ...

  4. golang 命令行_如何使用Golang编写快速有趣的命令行应用程序

    golang 命令行 by Peter Benjamin 彼得·本杰明(Peter Benjamin) 如何使用Golang编写快速有趣的命令行应用程序 (How to write fast, fun ...

  5. java命令行运行 package_使用命令行运行Java程序

    很久没有试过用Java命令行来运行程序了.今天用的时候都感觉有点不太顺利了.所以特别记下来,以免后边什么时候又忘掉. 首先是将编写好的Java程序放在某一文件夹下边.(本文以D盘javabasecod ...

  6. Cobra 快速入门 - 专为命令行程序而生

    最近一直在看 Istio(一个 Service Mesh 框架)相关的东西,当看到其源码时发现了一个新东西 Cobra,一查却发现这是个好东西,用的地方可不少,比如:Docker.Kubernetes ...

  7. c语言编写天气预报程序,在Deno中构建一个命令行天气预报程序

    在本文中,我将通过安装Deno运行时,并创建一个命令行天气程序,该程序将把一个城市名称作为参数,并返回未来24小时的天气预报. 要为Deno编写代码,我强烈建议将Visual Studio Code与 ...

  8. java命令行参数工具_Java方法中的参数太多,第8部分:工具

    java命令行参数工具 在我的系列文章的前七篇文章中,有关处理Java方法中期望的参数过多的内容集中在减少方法或构造函数期望的参数数量的替代方法上. 在本系列的第八篇文章中,我将介绍一些工具,这些工具 ...

  9. 使用click创建完美的Python命令行程序

    Python程序员的主要工作是写命令行程序,即直接在终端运行的脚本. 随着项目规模增长,我们希望创建有效的命令行接口,通过提供不同的参数,解决不同的问题,而不是每次都修改源代码. Click库是一个非 ...

最新文章

  1. Proovread安装与试用
  2. golang内置函数
  3. 前端如何实现音乐盒胶盘的转动_郑州Web前端入门教程之如何实现图片优化?
  4. 网友提问:当我要使用一个陌生的标准BAPI,我可以去哪里找到比较详尽的文档指导一类的资料
  5. 【转】10.Qt编程涉及的术语和名词
  6. 中livechart显示大数据_Servlet中利用jdbc加载显示数据
  7. 参考文献中英文人名_参考文献中英文人名的缩写规则
  8. 关于@Autowired的使用:推荐使用构造函数进行注入
  9. 用vue开发的h5商城小程序,thinkphp5开发拼团、砍价、秒杀、优惠券、积分、分销等功能
  10. uipath数据爬取(结构化数据)
  11. 微信小程序 首页弹出用户协议
  12. 华中师范大学计算机专硕和学硕,学硕?专硕?该如何选
  13. iphone打出空心心形_空心心形符号(类似的心形符号)
  14. 计算机之父童年的故事ppt,24计算机之父童年的故事
  15. 3月23日—3月27日四年级课程表
  16. 《指数基金投资指南》笔记整理
  17. [Codeup]1814 问题 A: 剩下的树
  18. 最简单的内网穿透教程
  19. ios播放本地声音文件
  20. MT6763 N1 色温模式功能的实现,手动调节色温。

热门文章

  1. GDUT2020新生赛——解题报告
  2. 546计算机综合什么意思,重装系统时出现File Name?(546)的错误该怎么解决?
  3. rtk打点,导入arcgis并进行格式变换
  4. 【深度学习,NLP,LM】Alpaca-Lora ,Colab上部署与调用
  5. 去耦电容和旁路电容的区别,终于有人说清楚了!
  6. IPV4子网掩码对应表
  7. 音响人烧电脑 篇一:花费700元,我是如何升级到i7级别的NAS
  8. 【锐捷】盒式设备恢复出厂配置
  9. 计算机中如何取消家长控制用户,Win7系统无法更改家长控制选项怎么解决
  10. OSGi框架学习------基本概念了解