1. 简介
本文将介绍 Airline —— 一个基于注解的 Java 库,用于快速构建命令行接口(CLI)。
如果你厌倦了手动解析 args[]
,还要写一堆 if-else
来处理参数,那 Airline 绝对能让你眼前一亮。它通过注解驱动的方式,把 CLI 的定义变得声明式、类型安全,而且代码干净得不像 Java(✅ 真的,不夸张)。
2. 使用场景
开发命令行工具时,我们通常希望用户能通过参数自定义行为,比如设置日志级别、数据库连接、开关功能等。Git CLI 就是个经典例子:简洁、直观、强大。
但 Java 原生处理命令行参数的方式太原始了,写起来啰嗦还容易出错。虽然有 Apache Commons CLI 这类工具,但配置依然繁琐。Airline 的出现就是为了解决这个问题:
✅ 用注解代替样板代码
✅ 自动支持 help、参数校验、互斥选项等常见需求
✅ 支持嵌套命令、子命令、复杂参数约束
我们接下来会实现一个模拟配置管理的 CLI 工具,支持:
- 设置日志级别(
setup-log
) - 配置数据库连接(
setup-db
) - 自动 help 提示
并通过这个例子,看看 Airline 能不能扛住真实场景的复杂度。
3. 项目依赖
先加 Maven 依赖:
<dependency>
<groupId>com.github.rvesse</groupId>
<artifactId>airline</artifactId>
<version>2.7.2</version>
</dependency>
搞定,就这一个依赖,无其他隐式依赖,轻量。
4. 快速搭建 CLI 入口
先定义主入口类 CommandLine
:
@Cli(name = "baeldung-cli",
description = "Baeldung Airline Tutorial",
defaultCommand = Help.class)
public class CommandLine {
public static void main(String[] args) {
Cli<Runnable> cli = new Cli<>(CommandLine.class);
Runnable cmd = cli.parse(args);
cmd.run();
}
}
关键点:
@Cli
注解定义 CLI 名称、描述和默认命令defaultCommand = Help.class
:不输入任何参数时,默认显示 helpHelp
是 Airline 内置的 help 命令,支持-h
或--help
就这么几行,一个带 help 的 CLI 框架就搭好了 ❗
5. 实现第一个命令:日志配置
我们来写一个 setup-log
命令,用于控制日志是否开启 verbose 模式。
@Command(name = "setup-log", description = "Setup our log")
public class LoggingCommand implements Runnable {
@Inject
private HelpOption<LoggingCommand> help;
@Option(name = { "-v", "--verbose" },
description = "Set log verbosity on/off")
private boolean verbose = false;
@Override
public void run() {
if (!help.showHelpIfRequested())
System.out.println("Verbosity: " + verbose);
}
}
关键细节解析
@Command
:声明这是一个 CLI 命令,用户输入setup-log
时触发@Inject HelpOption
:注入 help 功能,调用showHelpIfRequested()
可自动处理--help
@Option
:定义命令行选项,支持短名-v
和长名--verbose
- 实现
Runnable
接口,run()
方法里写业务逻辑
⚠️ 注意:help.showHelpIfRequested()
一定要先调用,否则 help 不会生效。
注册命令
别忘了把新命令注册到 @Cli
注解里:
@Cli(name = "baeldung-cli",
description = "Baeldung Airline Tutorial",
defaultCommand = Help.class,
commands = { LoggingCommand.class, Help.class })
public class CommandLine {
// main 方法不变
}
现在可以测试了:
$ java -jar cli.jar setup-log -v
Verbosity: true
$ java -jar cli.jar setup-log --help
# 自动生成格式化的 help 文档
是不是简单粗暴?连 help 文档都自动生成了 ✅
6. 复杂参数处理:数据库配置
真实场景中,参数往往更复杂。比如配置数据库时,我们可能需要:
- 指定数据库类型(仅限 mysql/postgresql/mongodb)
- 支持 URL 模式 或 host+port 模式(互斥)
- host 模式下必须提供用户名密码
- 可指定多个驱动 jar 包路径
Airline 全都能搞定。
6.1 枚举式参数限制
限制数据库类型只能是三种之一:
@AllowedRawValues(allowedValues = { "mysql", "postgresql", "mongodb" })
@Option(type = OptionType.COMMAND,
name = {"-d", "--database"},
description = "Type of RDBMS.",
title = "RDBMS type: mysql|postgresql|mongodb")
protected String rdbmsMode;
@AllowedRawValues
会自动校验输入值,非法值直接报错。
6.2 互斥参数(Mutually Exclusive)
URL 模式和 Host 模式不能同时出现:
@Option(type = OptionType.COMMAND,
name = {"--rdbms:url", "--url"},
description = "URL to use for connection to RDBMS.",
title = "RDBMS URL")
@MutuallyExclusiveWith(tag="mode")
@Pattern(pattern="^(http://.*):(\\d*)(.*)u=(.*)&p=(.*)")
protected String rdbmsUrl = "";
@Option(type = OptionType.COMMAND,
name = {"--rdbms:host", "--host"},
description = "Host to use for connection to RDBMS.",
title = "RDBMS host")
@MutuallyExclusiveWith(tag="mode")
protected String rdbmsHost = "";
@MutuallyExclusiveWith(tag="mode")
:标记这两个选项互斥@Pattern
:正则校验 URL 格式(注意 Java 字符串转义)
6.3 条件必填(Required Only If)
只有使用 host 模式时,才要求用户名密码:
@RequiredOnlyIf(names={"--rdbms:host", "--host"})
@Option(type = OptionType.COMMAND,
name = {"--rdbms:user", "-u", "--user"},
description = "User for login to RDBMS.",
title = "RDBMS user")
protected String rdbmsUser;
@RequiredOnlyIf(names={"--rdbms:host", "--host"})
@Option(type = OptionType.COMMAND,
name = {"--rdbms:password", "--password"},
description = "Password for login to RDBMS.",
title = "RDBMS password")
protected String rdbmsPassword;
@RequiredOnlyIf
指定依赖的选项名,满足条件时才校验必填。
6.4 多值参数(List 支持)
支持传多个 jar 包路径:
@Option(type = OptionType.COMMAND,
name = {"--driver", "--jars"},
description = "List of drivers",
title = "--driver <PATH_TO_YOUR_JAR> --driver <PATH_TO_YOUR_JAR>")
protected List<String> jars = new ArrayList<>();
用户可以这样用:
--driver /path/to/mysql.jar --driver /path/to/postgres.jar
Airline 会自动收集所有 --driver
的值放入 List
。
6.5 注册数据库命令
最后别忘了注册:
@Cli(
name = "baeldung-cli",
description = "Baeldung Airline Tutorial",
defaultCommand = Help.class,
commands = { LoggingCommand.class, DatabaseSetupCommand.class, Help.class }
)
7. 运行效果
默认 help 输出
$ baeldung-cli
usage: baeldung-cli <command> [ <args> ]
Commands are:
help Display help information
setup-db Setup our database
setup-log Setup our log
See 'baeldung-cli help <command>' for more information on a specific command.
命令级 help
$ baeldung-cli setup-log --help
NAME
baeldung-cli setup-log - Setup our log
SYNOPSIS
baeldung-cli setup-log [ {-h | --help} ] [ {-v | --verbose} ]
OPTIONS
-h, --help
Display help information
-v, --verbose
Set log verbosity on/off
实际调用示例
# 使用 URL 模式
$ baeldung-cli setup-db --database mysql --url "http://localhost:3306/db?u=admin&p=123"
# 使用 Host 模式(必须带用户密码)
$ baeldung-cli setup-db --database postgresql --host localhost --user admin --password secret
# 错误用法:混用互斥参数
$ baeldung-cli setup-db --url http://... --host localhost
# ❌ 报错:--url 和 --host 不能同时使用
8. 总结
Airline 真的是 Java CLI 开发的“提效神器”:
✅ 注解驱动,代码简洁:几乎不用写解析逻辑
✅ 功能完整:help、校验、互斥、依赖、多值全支持
✅ 类型安全:编译期检查命令结构
✅ 适合复杂 CLI:支持嵌套命令、全局选项、自定义解析器等高级特性
对于中大型命令行工具,尤其是需要发布给用户使用的,Airline 能大幅降低维护成本,避免各种参数解析的“坑”。
📌 踩坑提醒:
- 所有带
@Option
的字段必须是 非 private(至少 protected),否则反射访问不到@RequiredOnlyIf
等约束注解依赖字段名匹配,注意大小写和别名一致性- 多模块项目中,确保命令类能被正确加载(避免类加载问题)
完整代码已上传至 GitHub:https://github.com/baeldung/tutorials/tree/master/libraries-cli