JCommander + AutoService打造带子命令的Java命令行应用
文章目录
- 需求
- Java命令行工具库
- 依赖库
- 定义各个子命令
- 主类CLI
- 测试一下
- 参考文档
需求
最近想将自己的一个Java应用包装成命令行工具,看了几个库,最后选取了JCommander,结合AutoService库,实现了带子命令的工具,方便扩展新的子命令。
子命令放在同一包下,实现相同的接口,通过java.util.ServiceLocator加载。
Java命令行工具库
常用的几个库为:
-
JCommander
项目地址: https://github.com/cbeust/jcommander
Star: 1010 Fork: 227
文档地址: http://jcommander.org/ -
picocli
地址: https://github.com/remkop/picocli
Star: 336, Fork: 32
示例:https://github.com/kakawait/picocli-spring-boot-starter -
Commons CLI
地址: https://commons.apache.org/proper/commons-cli/
地址: 来自apache common的开源项目
更新: 最后一次更新是1.5-SNAPSHOT,是在2017年6月8日 -
Args4j
项目地址: https://0github.com/kohsuke/args4j
Star: 570 Fork: 151
文档地址: http://args4j.kohsuke.org/sample.html
活跃程度: 最后一次更新为2年之前
依赖库
<!-- https://mvnrepository.com/artifact/com.google.auto.service/auto-service --><dependency><groupId>com.google.auto.service</groupId><artifactId>auto-service</artifactId><version>1.1.1</version></dependency><!-- https://mvnrepository.com/artifact/com.beust/jcommander --><dependency><groupId>com.beust</groupId><artifactId>jcommander</artifactId><version>1.82</version></dependency>
定义各个子命令
Create子命令:
@AutoService(Command.class)
@Parameters(commandNames = { CREATE_CMD },commandDescription = "create a new ebook."
)
@Getter
public class CreateCommand implements Command{@Parameter(names = { "--indexUrl", "-u" })public String indexUrl;@Overridepublic void execute() throws CommandException {System.out.println("create a new book from " + indexUrl);}
}
Fetch子命令:
@AutoService(Command.class)
@Parameters(commandNames = {FETCH_CMD},commandDescription = "fetch some articles from website."
)
@Getter
public class FetchCommand implements Command {@Parameter(names = {"--indexUrl", "-u"})public String indexUrl;@Overridepublic void execute() throws CommandException {System.out.println("fetch articles from " + indexUrl);}
}
都实现了接口Command:
public interface Command {default Collection<Command> commands() {return null;}void execute() throws CommandException;
}
注意,子命令支持嵌套的子命令。当然一般用不到。
主类CLI
public class CLI {static final String CREATE_CMD = "create";static final String FETCH_CMD = "fetch";@Parameter(names = { "-h", "--help" }, help = true)private boolean help;public void exec(String[] args) {final JCommander.Builder builder = JCommander.newBuilder().addObject(new CLI()); final JCommander jCommander = builder.build();ServiceLoader.load(Command.class).forEach(command -> CLI.registerCommand(jCommander, command));JCommander leafCommander = jCommander;try {jCommander.parse(args);final String rootVerb = jCommander.getParsedCommand();final JCommander rootCommander = jCommander.getCommands().get(rootVerb);if (rootCommander == null) {jCommander.usage();System.exit(1);}leafCommander = rootCommander;do {final String subVerb = leafCommander.getParsedCommand();final JCommander subCommander = leafCommander.getCommands().get(subVerb);if (subCommander != null)leafCommander = subCommander;elsebreak;} while (true);final Command command = (Command) leafCommander.getObjects().get(0);command.execute();} catch (final CommandException e) {System.err.printf("%1$s: %2$s. See '%1$s --help'.%n", leafCommander.getProgramName(), e.getMessage());System.exit(e.getStatus());} catch (final Exception e) {System.err.printf("%1$s: %2$s. See '%1$s --help'.%n", leafCommander.getProgramName(), e.getMessage());System.exit(1);}}private static final void registerCommand(final JCommander jCommander, final Command command) {jCommander.addCommand(command);final Parameters commandParameters = command.getClass().getAnnotation(Parameters.class);if (commandParameters == null || commandParameters.commandNames().length == 0)return;final JCommander subCommander = jCommander.getCommands().get(commandParameters.commandNames()[0]);final Collection<Command> subCommands = command.commands();if (subCommands != null)subCommands.forEach(subCommand -> CLI.registerCommand(subCommander, subCommand));}public static void main(final String[] args) {CLI cli = new CLI();cli.exec(args);}
}
原理很简单:ServiceLocator加载了所有Command的实现类,然后根据子命令调用相应的Command类。AutoService的好处就是不必自己去创建META-INF/services下的相关文件。
测试一下
@Testpublic void testCreateCommand() {CLI cli = new CLI();String[] argv = { "create", "-u", "http://www.sina.com.cn"};cli.exec(argv);}@Testpublic void testFetchCommand() {CLI cli = new CLI();String[] argv = { "fetch", "-u", "http://www.csdn.cn"};cli.exec(argv);}
参考文档
- https://gist.github.com/mkarg/9d9ca23e6da32b47c7fadaf10ae16ba6
- https://pedrorijo.com/blog/java-service-loader/
相关文章:
JCommander + AutoService打造带子命令的Java命令行应用
文章目录 需求Java命令行工具库依赖库定义各个子命令主类CLI测试一下参考文档 需求 最近想将自己的一个Java应用包装成命令行工具,看了几个库,最后选取了JCommander,结合AutoService库,实现了带子命令的工具,方便扩展…...
pycharm运行pytest无法实时输出信息
需要去掉控制台输出。根据查询相关信息显示pycharm运行pytest无法实时输出信息,需要去掉pycharm里面的运行模式,点击减号,再点击加号,添加python执行文件即可实时输出信息。 问题描述: 使用pycharm运行代码时&#x…...
Mac 卸载 IntelliJ IDEA 方法
Mac 系统下 IDEA 没有一键卸载程序,也没有完全卸载的插件,若要彻底删除,除了在应用(Application)里删除 IDEA 到垃圾桶外,还需要在终端(Terminal)执行删除相应的文件及文件夹。 1 分…...
数据安全能力框架模型-详细解读(三)
数据安全能力框架内涵 “奇安信数据安全能力框架”体现了数据安全治理从组织机构安全治理,到数字化环境具体管控、分析能力分层逐步落实的工程方法。 它以企业数据安全的战略目标和风险容忍度为输入,明确数据安全治理的组织;以合规与治理需…...
vscode启动leiningen项目
要在 VS Code 中启动 Leiningen 项目,你可以按照以下步骤进行操作: 确保已经安装了 Leiningen。你可以在终端中输入 lein version 来检查是否已成功安装。 在 VS Code 中安装 Leiningen 扩展。打开 VS Code,点击左侧的扩展图标(四…...
Qt事件的传递顺序
事件的传递顺序 事件的传递顺序是这样的:先是事件过滤器,然后是该部件的event()函数,最后是该部件的事件处理函数。这里还要注意,event()函数和事件处理函数,是在该部件内进行重新定义的,而事件过滤器却是…...
基于facenet+faiss开发构建人脸识别系统
facenet是一款非常经典的神经网络模型,它可以直接学习从人脸图像到欧几里德空间的映射(直接将人脸映射到欧几里得空间)。在欧几里德空间中,距离直接对应于人脸相似性的度量。一旦这个空间产生,使用标准技术,将FaceNet嵌入作为特征…...
数据分析的心脏:获取数据的好工具
打开网站:Scrape and Monitor Data from Any Website with No Code 新建机器人: 选择类型: 填写目标网站网址: 输入网址:https://cn.wsj.com/zh-hans/news/technology 第一次录制需要安装chrome插件: 并设置…...
【万字长文】SpringBoot整合Atomikos实现多数据源分布式事务(提供Gitee源码)
前言:在最近的实际开发的过程中,遇到了在多数据源的情况下要保证原子性的问题,这个问题当时遇到了也是思考了一段时间,后来通过搜集大量资料与学习,最后是采用了分布式事务来解决这个问题,在讲解之前&#…...
js中什么是宏任务、微任务?宏任务、微任务有哪些?又是怎么执行的?
目录 目录 目录 参考资料 必看强烈建议十分钟看完视频 ,即可学会 必看参考详解宏任务微任务 参考资料 1 宏任务与微任务_哔哩哔哩_bilibili 什么是宏任务、微任务?宏任务、微任务有哪些?又是怎么执行的?_什么是宏任务和微任…...
Word中如何断开表格中线段
Word中如何断开表格中线段_word表格断线怎么弄_仰望星空_LiDAR的博客-CSDN博客有时候为了美观,需要实现如下的效果,即第2条线段被断开成3段步骤如下:选中需要断开的格网,如下,再选择段落、针对下框标即可。_word表格断…...
大数据指标体系-笔记
指标体系 1 总体流程图 1.1 2 模型‘ 2.1 OSM OSM(Object,Strategy,Measure) 「业务度量」涉及到以下两个概念:一个是KPI ,用来直 接衡量策略的有效性;一个是Target,是预先给出的值,用来判断是否达到预期 2.2 UJM User, Journey, Map 2.3 AARRR-海盗 AARRR(Acquisitio…...
Arthas协助MQ消费性能优化
背景 项目中使用AWS的SQS消息队列进行异步处理,QA通过压测发现单机TPS在23左右,目标性能在500TPS,所以需要对消费逻辑进行优化,提升消费速度。 目标 消费TPS从23提升到500 优化流程 优化的思路是先分析定位性能瓶颈ÿ…...
【Linux】【docker】安装sonarQube免费社区版9.9
文章目录 ⛺sonarQube 镜像容器⛺Linux 安装镜像🍁出现 Permission denied的异常🍁安装sonarQube 中文包🍁重启服务 ⛺代码上传到sonarQube扫描🍁java语言配置🍁配置 JS TS Php Go Python⛏️出现异常sonar-scanner.ba…...
C/C++实现librosa音频处理库melspectrogram和mfcc
C/C实现librosa音频处理库melspectrogram和mfcc 目录 C/C实现librosa音频处理库melspectrogram和mfcc 1.项目结构 2.依赖环境 3.C librosa音频处理库实现 (1) 对齐读取音频文件 (2) 对齐melspectrogram (3) 对齐MFCC 4.Demo运行 5.librosa库C源码下载 深度学习语音处…...
浪潮服务器硬盘指示灯显示黄色的服务器数据恢复案例
服务器数据恢复环境: 宁夏某市某单位的一台浪潮服务器,该服务器中有一组由6块SAS硬盘组建的RAID5阵列。 服务器上存放的是Oracle数据库文件,操作系统层面划分了1个卷。 服务器故障&初检: 服务器在运行过程中有两块磁盘的指示灯…...
宋浩概率论笔记(三)随机向量/二维随机变量
第三更:本章的内容最重要的在于概念的理解与抽象,二重积分通常情况下不会考得很难。此外,本次暂且忽略【二维连续型随机变量函数的分布】这一章节,非常抽象且难度较高,之后有时间再更新。...
附件展示 点击下载
效果图 实现代码 <el-table-column prop"attachment" label"合同附件" width"250" show-overflow-tooltip><template slot-scope"scope"><div v-if"scope.row.cceedcAppendixInfoList &&scope.row.ccee…...
HotSpot虚拟机之Class文件及字节码指令
目录 一、javac编译 1. 编译过程 2. 语法糖 二、Class文件 1. 文件格式 2. 常量池项目 3. 属性类型 三、Class文件实例 1. 源代码 2. javap分析Class文件 四、字节码指令 五、参考资料 一、javac编译 1. 编译过程 javac命令由Java语言编写,目的将Ja…...
关于盐雾试验
盐雾实验一般被称为盐雾试验,是一种主要利用盐雾试验设备所创造的人工模拟盐雾环境条件来考核产品或金属材料耐腐蚀性能的环境试验。 盐雾实验的主要目的是考核产品或金属材料的耐盐雾腐蚀性能,盐雾试验结果也是对产品质量的判定,是正确衡量…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
