这段代码是 Tomcat8RunnerCli ------ 它是 Tomcat8Runner 的 命令行接口(CLI)入口类,用于解析用户传入的参数,并启动内嵌 Tomcat。
你可以把它理解为:"可执行 WAR 文件的 main() 方法所在类" ,负责把命令行参数(如 -httpPort 9090)转换成 Java 对象配置,然后交给 Tomcat8Runner 去真正启动服务器。
🎯 一、核心作用
提供友好的命令行参数支持,让用户通过
java -jar app.war [options]灵活控制内嵌 Tomcat 的行为。
例如:
bash
java -jar myapp.war -httpPort 8081 -debug -Dmy.prop=value
🔧 二、关键组成部分解析
1. 使用 Apache Commons CLI 定义命令行选项
所有 Option 都通过 OptionBuilder 声明,比如:
java
static Option httpPort = OptionBuilder
.withArgName("httpPort")
.hasArg() // 需要参数值
.withDescription("http port to use")
.create("httpPort"); // 长选项名
支持的选项包括:
| 选项 | 说明 |
|---|---|
-httpPort N |
HTTP 端口(默认由配置文件决定) |
-httpsPort N |
HTTPS 端口 |
-ajpPort N |
AJP 端口 |
-serverXmlPath file |
使用自定义 server.xml |
-resetExtract |
强制重新解压 WAR 内容 |
-Dkey=value |
设置系统属性(类似 JVM 的 -D) |
-obfuscate password |
直接混淆密码并退出 (调用 PasswordUtil.obfuscate()) |
-debug 或 -X |
启用调试日志 |
-help 或 -h |
打印帮助信息 |
✅ 这些选项覆盖了 Tomcat 启动所需的核心配置。
2. 优先级机制:命令行 > 配置文件
程序会先加载一个内置配置文件:
java
// 从 JAR 内部读取 /tomcat.standalone.properties
Properties props = buildStandaloneProperties();
但 命令行参数优先级更高:
java
// 先读配置文件中的端口
port = props.getProperty(Tomcat8Runner.HTTP_PORT_KEY);
if (port != null) tomcat8Runner.httpPort = Integer.parseInt(port);
// 如果命令行指定了,则覆盖
if (line.hasOption(httpPort)) {
tomcat8Runner.httpPort = Integer.parseInt(line.getOptionValue(httpPort));
}
💡 这是典型的"默认值 + 覆盖"设计模式。
3. 特殊功能:密码混淆工具
java
if (line.hasOption(obfuscate)) {
System.out.println(PasswordUtil.obfuscate(line.getOptionValue(obfuscate)));
System.exit(0);
}
这意味着你可以这样使用:
bash
java -jar myapp.war -obfuscate mypassword
# 输出:OBF:1v2j1uum1xtv1uvk1v0h1v2j
✅ 把可执行 WAR 当作一个 密码混淆工具 来用,非常方便!
4. 系统属性注入(-Dkey=value)
java
if (line.hasOption(sysProps)) {
Properties sysProps = line.getOptionProperties('D');
for (entry : sysProps) {
System.setProperty(key, value); // 注入到 JVM 系统属性
}
}
这让你可以:
bash
java -jar app.war -Djavax.net.ssl.keyStore=keystore.jks -Dwars=app.war
→ 这些属性会被 Tomcat8Runner 读取(比如用于 HTTPS 或 WAR 列表)。
5. 帮助信息(HelpFormatter)
当参数错误或使用 -h 时,自动打印用法:
text
usage: java -jar [path to your exec war jar]
-ajpPort <ajpPort> ajp port to use
-clientAuth enable client authentication for https
-debug debug
-extractDirectory <extract...> path to extract war content...
-help help
-httpPort <httpPort> http port to use
-httpsPort <httpsPort> https port to use
-obfuscate <password> obfuscate the password and exit
...
🔄 三、整体工作流程(main() 方法)
-
解析命令行参数
- 使用
GnuParser(支持 GNU 风格,如-Dkey=value) - 失败则打印帮助并退出
- 使用
-
处理特殊命令
-help→ 打印帮助-obfuscate xxx→ 混淆密码并退出
-
加载默认配置
- 从 JAR 内部的
tomcat.standalone.properties读取默认值
- 从 JAR 内部的
-
应用命令行覆盖
- 将 CLI 参数赋值给
Tomcat8Runner实例
- 将 CLI 参数赋值给
-
启动 Tomcat
javatomcat8Runner.run(); // 进入真正的启动逻辑
📦 四、与 Tomcat8Runner 的关系
| 类 | 职责 |
|---|---|
Tomcat8RunnerCli |
命令行解析 + 配置组装(面向用户) |
Tomcat8Runner |
实际启动 Tomcat + 部署应用(面向运行) |
✅ 分离关注点:CLI 只负责"怎么启动",Runner 负责"启动什么"。
在构建可执行 WAR 时,Maven 插件会设置:
xml
<Main-Class>Tomcat8RunnerCli</Main-Class>
所以 java -jar app.war 实际执行的是 Tomcat8RunnerCli.main()。
✅ 五、典型使用场景
场景 1:快速启动 Web 应用
bash
java -jar myapp-exec.war -httpPort 9090
场景 2:生成混淆密码
bash
java -jar myapp-exec.war -obfuscate admin123
# 得到 OBF:xxx,用于配置文件
场景 3:调试部署问题
bash
java -jar myapp.war -debug -resetExtract
场景 4:启用 HTTPS
bash
java -jar myapp.war \
-httpsPort 8443 \
-Djavax.net.ssl.keyStore=keystore.jks \
-Djavax.net.ssl.keyStorePassword=secret
🧠 总结:一句话理解
Tomcat8RunnerCli是可执行 WAR 的"命令行门面",它将用户输入的参数转化为结构化配置,驱动内嵌 Tomcat 启动,同时提供密码混淆等实用工具功能。
它是 传统 WAR 应用实现"单文件交付 + 灵活配置"体验的关键一环,让 Java Web 应用像脚本一样简单运行。
如果你正在使用 Maven 的 tomcat7-maven-plugin 的 exec-war 目标,那么你生成的可执行 WAR 就是靠这个类来启动的!