Ubuntu 22.04 安装 Apache Commons Exec 指南

在 Ubuntu 22.04 从零搭建 Apache Commons Exec 1.6.0 环境:装 JDK 17 与 Maven,给出 Maven 依赖与官方发行包两种获取方案,含 sha512 校验、验证程序、多版本管理与卸载。

Apache Commons ExecApache Commons Exec2026/10/14

Ubuntu 22.04 安装 Apache Commons Exec 指南

目标:在一台全新的 Ubuntu 22.04 服务器上搭建可编译、可运行 Apache Commons Exec 的 Java 环境,覆盖 JDK 17 与 Maven 安装、jar 的两种获取方式(Maven 依赖 / 官方发行包手动下载)、sha512 校验、最小验证程序编译运行、多版本管理与卸载。全部命令与回显已在 Ubuntu 22.04(JDK 17 + Maven 3.6.3)实测通过。

Apache Commons Exec 是 Apache 基金会提供的 Java 库,用于在 JVM 内可靠地执行并管理外部进程:它封装了 Runtime.exec / ProcessBuilder 的繁琐细节,补上了超时看门狗、流泵、异步回调等能力。本文先给出环境与版本,再逐一实测两条获取 jar 的路线。

💡 技术拓展:在 JVM 里执行外部命令,业界有多种方案,选型前先看清各自边界。

方案所属特点适用场景
Runtime.exec()JDK 内置最简单,无超时、无流处理,易造成管道缓冲区死锁一次性简单调用
ProcessBuilderJDK 内置支持重定向与合并输出流,但超时/异步仍需自行实现可控的中等复杂度调用
JNA / JNI第三方 / 原生直接调用系统 API,能力最强但需平台库,部署重需操作系统级控制的场景
Apache Commons Exec独立库统一封装执行、流泵、超时看门狗、异步结果处理,零传递依赖需要超时控制与输出捕获的工程

本文实际采用 Apache Commons Exec 1.6.0,理由是它把「执行 + 超时 + 输出捕获 + 异步回调」一次性封装,且自身不引入任何运行期传递依赖,接入成本最低。

一、环境信息

本章确认系统版本,安装 JDK 17 与 Maven,为后续获取 Commons Exec 做准备。Commons Exec 1.6.0 的字节码目标是 Java 8(jar 内清单 X-Compile-Source-JDK: 1.8、X-Compile-Target-JDK: 1.8),因此 JDK 8 及以上均可运行,本文统一使用 JDK 17 作为开发与运行环境。

先确认系统版本:

cat /etc/os-release | grep -E "^(NAME|VERSION)="

实测回显:

NAME="Ubuntu"
VERSION="22.04.5 LTS (Jammy Jellyfish)"

安装 JDK 17 与 Maven(约 1~2 分钟,取决于网络):

sudo apt update
sudo apt install -y openjdk-17-jdk maven

实测回显(输出节选,实测首尾):

The following additional packages will be installed:
  openjdk-17-jdk-headless openjdk-17-jre openjdk-17-jre-headless
The following NEW packages will be installed:
  openjdk-17-jdk-headless openjdk-17-jre openjdk-17-jre-headless
Setting up openjdk-17-jre-headless:amd64 (17.0.20.1+1-1~22.04) ...
Setting up openjdk-11-jre-headless:amd64 (11.0.32.1+1-1ubuntu1~22.04) ...
Setting up maven (3.6.3-5) ...
Setting up openjdk-17-jdk-headless:amd64 (17.0.20.1+1-1~22.04) ...
Setting up openjdk-17-jdk:amd64 (17.0.20.1+1-1~22.04) ...

验证安装结果:

java -version
javac -version
mvn -v

实测回显:

openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
javac 17.0.20.1
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 17.0.20.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: en, platform encoding: UTF-8
OS name: "linux", version: "6.8.0-138-generic", arch: "amd64", family: "unix"

输出中 Java version: 17.0.20.1 说明 Maven 已使用刚安装的 JDK 17。查看 java 命令的候选与最终指向:

update-alternatives --list java
readlink -f $(which java)

实测回显:

/usr/lib/jvm/java-11-openjdk-amd64/bin/java
/usr/lib/jvm/java-17-openjdk-amd64/bin/java
/usr/lib/jvm/java-17-openjdk-amd64/bin/java

Ubuntu 22.04 的 openjdk-17-jdk 安装后会自动把 java 指向 17,readlink 结果确认当前生效的就是 java-17-openjdk-amd64,无需手工切换。若 mvn -v 显示的 Java version 不是 17,可在 ~/.bashrc 中追加 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 后重新登录。

二、版本选型

Commons Exec 遵循「最新稳定版挂在官方下载目录、历史版本进归档仓库」的发布策略,选型时建议直接使用最新稳定版。下表列出常用版本(JDK 要求以各版本 jar 清单与官方发布说明为准):

版本发布状态JDK 要求运行期传递依赖适用场景
1.6.0最新稳定版(2025)Java 8 及以上无(零传递依赖)新项目首选
1.5.0稳定版Java 8 及以上无1.6.0 有兼容顾虑时的回退
1.4.0稳定版Java 8 及以上无存量项目锁版本
1.3维护期版本Java 6 及以上无老系统兼容

关于「JDK 要求」的实测依据:解出 1.6.0 的 jar 清单,其中 X-Compile-Source-JDK: 1.8、X-Compile-Target-JDK: 1.8、Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" 三处都表明 1.6.0 的字节码目标是 Java 8,因此 JDK 8/11/17/21 都能运行(本文用 JDK 17 实测)。

本文统一采用以下坐标与下载地址(均实测有效):

Maven 坐标:org.apache.commons:commons-exec:1.6.0
发行包:https://downloads.apache.org/commons/exec/binaries/commons-exec-1.6.0-bin.tar.gz
校验文件:https://downloads.apache.org/commons/exec/binaries/commons-exec-1.6.0-bin.tar.gz.sha512
中央仓库 jar:https://repo1.maven.org/maven2/org/apache/commons/commons-exec/1.6.0/commons-exec-1.6.0.jar
sha512(实测):
60dc9f43743b470ebcc5293773f0b166d2213f151180018a545fdc4076f7e8f38fa8c094ea56f4846bf10636d57a520f274f693a38d8ff7adcfe77b584c22e91

两点实测结论需要提前知道:

  1. downloads.apache.org 只保留最新版。实测访问旧版地址 https://downloads.apache.org/commons/exec/binaries/commons-exec-1.4.0-bin.tar.gz 返回 404,旧版需到 https://archive.apache.org/dist/commons/exec/binaries/ 下载(实测返回 200)。
  2. Commons Exec 是零运行期传递依赖的库。1.6.0 的 pom 中 <dependencies> 只有 JUnit 等 test 作用域条目,手动安装时只需要一个主 jar,无需额外放依赖。

三、方案A:Maven 中央仓库依赖

方案A通过 Maven 自动解析并下载 jar,是工程化项目的推荐做法。先创建项目骨架:

mkdir -p /opt/exec-demo/src/main/java/net/quzuo/demo
cd /opt/exec-demo

该命令无输出。写入 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.quzuo.demo</groupId>
  <artifactId>exec-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-exec</artifactId>
      <version>1.6.0</version>
    </dependency>
  </dependencies>
</project>

逐项说明:maven.compiler.source/target 按 Java 17 语法编译;project.build.sourceEncoding 强制源码 UTF-8(否则中文字符串会报 unmappable character);dependencies 只声明 commons-exec,因为它没有运行期传递依赖。

验证依赖解析结果:

mvn dependency:tree

实测回显(输出节选,实测首尾):

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ exec-demo ---
[INFO] net.quzuo.demo:exec-demo:jar:1.0.0
[INFO] \- org.apache.commons:commons-exec:jar:1.6.0:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

依赖树中只有 commons-exec 一行,直观证明零传递依赖。写入验证程序 src/main/java/net/quzuo/demo/HelloExec.java:

package net.quzuo.demo;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;

public class HelloExec {

    public static void main(String[] args) throws Exception {
        run("ls -l /opt/commons");
        run("echo hello commons exec");
        Package pkg = CommandLine.class.getPackage();
        System.out.println("commons-exec 版本: " + pkg.getImplementationVersion());
        System.out.println("验证通过");
    }

    private static void run(String command) throws Exception {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayOutputStream err = new ByteArrayOutputStream();
        DefaultExecutor executor = DefaultExecutor.builder()
                .setExecuteStreamHandler(new PumpStreamHandler(out, err))
                .get();
        int exitValue = executor.execute(CommandLine.parse(command));
        System.out.println("命令: " + command);
        System.out.println("退出码: " + exitValue);
        System.out.print(out.toString(StandardCharsets.UTF_8));
    }
}

程序逻辑:用 CommandLine.parse 把命令字符串拆成可执行文件与参数;用 DefaultExecutor.builder() 构造执行器并注入 PumpStreamHandler 捕获 stdout/stderr;execute 为同步调用,返回子进程退出码;最后从 jar 清单打印库版本。注意 1.6.0 中直接 new DefaultExecutor() 已标记为弃用,本文统一使用 builder 形态。

编译并生成运行类路径,然后运行:

mvn -q compile
mvn -q dependency:build-classpath -Dmdep.outputFile=/tmp/cp.txt
cat /tmp/cp.txt
java -Dfile.encoding=UTF-8 -cp "target/classes:$(cat /tmp/cp.txt)" net.quzuo.demo.HelloExec

实测回显:

/root/.m2/repository/org/apache/commons/commons-exec/1.6.0/commons-exec-1.6.0.jar
命令: ls -l /opt/commons
退出码: 0
total 884
drwxr-xr-x 3 root root   4096 Oct 13 16:25 commons-exec-1.6.0
-rw-r--r-- 1 root root 893502 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz
-rw-r--r-- 1 root root    129 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz.sha512
命令: echo hello commons exec
退出码: 0
hello commons exec
commons-exec 版本: 1.6.0
验证通过

程序成功驱动 ls -l 与 echo 两个外部命令,捕获到它们的标准输出,并从 jar 清单读到 1.6.0,方案A安装完成。

四、方案B:官方发行包手动安装

方案B适合没有 Maven 的机器:直接把官方发行包放到本地目录,用 java -cp 运行。先下载发行包与校验文件:

sudo mkdir -p /opt/commons
cd /opt/commons
sudo curl -fsSLO https://downloads.apache.org/commons/exec/binaries/commons-exec-1.6.0-bin.tar.gz
sudo curl -fsSLO https://downloads.apache.org/commons/exec/binaries/commons-exec-1.6.0-bin.tar.gz.sha512
ls -l

实测回显:

total 880
-rw-r--r-- 1 root root 893502 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz
-rw-r--r-- 1 root root    129 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz.sha512

.sha512 文件内容是裸哈希(128 个十六进制字符加换行)。校验时先看内容,再拼成 哈希 文件名 的标准格式交给 sha512sum -c:

cat commons-exec-1.6.0-bin.tar.gz.sha512
printf '%s  %s\n' "$(cat commons-exec-1.6.0-bin.tar.gz.sha512)" commons-exec-1.6.0-bin.tar.gz | sha512sum -c -

实测回显:

60dc9f43743b470ebcc5293773f0b166d2213f151180018a545fdc4076f7e8f38fa8c094ea56f4846bf10636d57a520f274f693a38d8ff7adcfe77b584c22e91
commons-exec-1.6.0-bin.tar.gz: OK

OK 表示下载件与官方发布的 sha512 完全一致。解压并查看发行包结构:

sudo tar xzf commons-exec-1.6.0-bin.tar.gz
ls -l commons-exec-1.6.0/*.jar

实测回显:

-rw-r--r-- 1 root root 444682 Nov 25  2025 commons-exec-1.6.0/commons-exec-1.6.0-javadoc.jar
-rw-r--r-- 1 root root  69399 Nov 25  2025 commons-exec-1.6.0/commons-exec-1.6.0-sources.jar
-rw-r--r-- 1 root root  57061 Nov 25  2025 commons-exec-1.6.0/commons-exec-1.6.0-test-sources.jar
-rw-r--r-- 1 root root  71154 Nov 25  2025 commons-exec-1.6.0/commons-exec-1.6.0-tests.jar
-rw-r--r-- 1 root root  69316 Nov 25  2025 commons-exec-1.6.0/commons-exec-1.6.0.jar

发行包内没有 lib/ 目录,因为 Commons Exec 零传递依赖,运行期只需要 commons-exec-1.6.0.jar 这一个文件(其余为源码包、javadoc 包与测试包)。先实测一个必踩的坑——该 jar 清单里没有 Main-Class,java -jar 无法直接启动:

cd /opt/commons
java -jar commons-exec-1.6.0/commons-exec-1.6.0.jar
echo "退出码: $?"

实测回显:

no main manifest attribute, in commons-exec-1.6.0/commons-exec-1.6.0.jar
退出码: 1

正确做法是用 -cp 指定主 jar。把第三章的验证程序复制到 /opt/commons/(去掉 package 行)后编译运行:

cd /opt/commons
export LANG=C.UTF-8
javac -encoding UTF-8 -cp commons-exec-1.6.0/commons-exec-1.6.0.jar HelloExec.java
java -Dfile.encoding=UTF-8 -cp ".:commons-exec-1.6.0/commons-exec-1.6.0.jar" HelloExec

实测回显:

命令: ls -l /opt/commons
退出码: 0
total 892
-rw-r--r-- 1 root root   2091 Oct 13 16:34 HelloExec.class
-rw-r--r-- 1 root root   1177 Oct 13 16:34 HelloExec.java
drwxr-xr-x 3 root root   4096 Oct 13 16:25 commons-exec-1.6.0
-rw-r--r-- 1 root root 893502 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz
-rw-r--r-- 1 root root    129 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz.sha512
命令: echo hello commons exec
退出码: 0
hello commons exec
commons-exec 版本: 1.6.0
验证通过

注意 Linux 类路径分隔符是冒号 :(Windows 是分号)。方案B安装完成。

五、方案对比与选型建议

对比项方案A:Maven 依赖方案B:发行包手动安装
依赖管理自动解析,改版本只需改一处手动下载,需自行维护 jar 文件
升级成本改一行版本号重新构建重新下载、校验、替换 jar
离线部署需内网私服或预先缓存到本地仓库天然离线友好
可复现性pom 锁版本,强依赖脚本与人为记录
适用场景一切有构建工具的工程无 Maven 的跳板机、快速验证、交付现场

选型建议:开发 / CI 环境一律方案A;目标机器没有 Maven 或需要临时排查时用方案B。由于 Commons Exec 零传递依赖,方案B的类路径极简——只需一个主 jar,这也是它比多数 Java 库更容易手工部署的原因。需要说明的是,方案A在 Ubuntu 22.04 上几乎无额外前置(java 已自动指向 17),而方案B额外依赖 javac 与 -encoding UTF-8 的正确设置。

六、多版本管理

用「版本目录 + current 符号链接」方式管理多版本:所有版本平铺在 /opt/commons/ 下,每个版本目录内放一个 lib/,current 指向当前生效版本。本次实测同时部署 1.6.0(发行包解压得到)与 1.4.0(从中央仓库下载):

cd /opt/commons
sudo mkdir -p commons-exec-1.6.0/lib commons-exec-1.4.0/lib
sudo cp commons-exec-1.6.0/commons-exec-1.6.0.jar commons-exec-1.6.0/lib/
sudo curl -fsSL -o commons-exec-1.4.0/lib/commons-exec-1.4.0.jar https://repo1.maven.org/maven2/org/apache/commons/commons-exec/1.4.0/commons-exec-1.4.0.jar
sudo ln -sfn commons-exec-1.6.0 current
ls -l

实测回显:

total 896
-rw-r--r-- 1 root root   2350 Oct 13 16:34 HelloExec.class
-rw-r--r-- 1 root root   1177 Oct 13 16:34 HelloExec.java
drwxr-xr-x 3 root root   4096 Oct 13 16:35 commons-exec-1.4.0
drwxr-xr-x 4 root root   4096 Oct 13 16:35 commons-exec-1.6.0
-rw-r--r-- 1 root root 893502 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz
-rw-r--r-- 1 root root    129 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz.sha512
lrwxrwxrwx 1 root root     18 Oct 13 16:35 current -> commons-exec-1.6.0

current 指向 1.6.0。用 current 链接编译运行验证程序(复用第四章的 HelloExec.java):

cd /opt/commons
export LANG=C.UTF-8
javac -encoding UTF-8 -cp "current/lib/*" HelloExec.java -d out
java -Dfile.encoding=UTF-8 -cp "out:current/lib/*" HelloExec

实测回显:

命令: ls -l /opt/commons
退出码: 0
total 900
-rw-r--r-- 1 root root   2350 Oct 13 16:34 HelloExec.class
-rw-r--r-- 1 root root   1177 Oct 13 16:34 HelloExec.java
drwxr-xr-x 3 root root   4096 Oct 13 16:35 commons-exec-1.4.0
drwxr-xr-x 4 root root   4096 Oct 13 16:35 commons-exec-1.6.0
-rw-r--r-- 1 root root 893502 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz
-rw-r--r-- 1 root root    129 Oct 13 16:25 commons-exec-1.6.0-bin.tar.gz.sha512
lrwxrwxrwx 1 root root     18 Oct 13 16:35 current -> commons-exec-1.6.0
drwxr-xr-x 2 root root   4096 Oct 13 16:35 out
命令: echo hello commons exec
退出码: 0
hello commons exec
commons-exec 版本: 1.6.0
验证通过

切换到 1.4.0 再运行:

sudo ln -sfn commons-exec-1.4.0 current
ls -l current
java -Dfile.encoding=UTF-8 -cp "out:current/lib/*" HelloExec

实测回显:

lrwxrwxrwx 1 root root 18 Oct 13 16:35 current -> commons-exec-1.4.0
命令: ls -l /opt/commons
退出码: 0
total 900
-rw-r--r-- 1 root root   2350 Oct 13 16:34 HelloExec.class
(清单中间若干行未列出)
命令: echo hello commons exec
退出码: 0
hello commons exec
commons-exec 版本: 1.4.0
验证通过

程序打印的版本号随符号链接同步变为 1.4.0,证明切换生效。切回最新版:

sudo ln -sfn commons-exec-1.6.0 current

该命令无输出。关键约束:编译和运行都必须引用 current 路径,任何一处写死版本号目录,切换都会失效。

七、卸载

卸载分三部分:手动安装目录、Maven 本地仓库缓存、apt 安装的软件包。清理手动目录与缓存:

sudo rm -rf /opt/commons
rm -rf ~/.m2/repository/org/apache/commons/commons-exec

该命令无输出,验证已删除:

ls /opt/commons
ls ~/.m2/repository/org/apache/commons/commons-exec

实测回显:

ls: cannot access '/opt/commons': No such file or directory
ls: cannot access '/root/.m2/repository/org/apache/commons/commons-exec': No such file or directory

卸载软件包时有一个实测坑:apt-get remove openjdk-17-jdk maven 只会移除两个元包,真正提供 java/javac 的 openjdk-17-jdk-headless、openjdk-17-jre 仍在系统里:

sudo apt-get remove -y openjdk-17-jdk maven
java -version

实测回显(输出节选,实测首尾):

The following packages will be REMOVED:
  maven openjdk-17-jdk
Removing maven (3.6.3-5) ...
Removing openjdk-17-jdk:amd64 (17.0.20.1+1-1~22.04) ...
openjdk version "17.0.20.1" 2026-08-18

java -version 仍能输出,说明 headless 包未清。要彻底移除需连带 purge 依赖包:

sudo apt-get purge -y openjdk-17-jdk-headless
sudo apt-get autoremove -y
java -version
javac -version
mvn -v

实测回显(输出节选,实测首尾):

Removing openjdk-17-jdk-headless:amd64 (17.0.20.1+1-1~22.04) ...
Removing libjpeg-turbo8:amd64 (2.1.2-0ubuntu1) ...
Processing triggers for ca-certificates (20260601~22.04.1) ...
bash: java: command not found
bash: javac: command not found
bash: mvn: command not found

java -version、javac -version、mvn -v 三条命令全部报 command not found,卸载完成。

八、FAQ

Q1:编译时提示 unmappable character for encoding US-ASCII 怎么解决? 源码含中文字符串时,若系统 locale 为 POSIX、javac 默认按 US-ASCII 解码就会报此错(实测 33 处错误)。编译时显式加 -encoding UTF-8、运行加 -Dfile.encoding=UTF-8,并 export LANG=C.UTF-8 即可(见第四章实测)。

Q2:java -jar commons-exec-1.6.0.jar 为什么起不来? 实测回显为 no main manifest attribute。Commons Exec 是库而非可执行程序,jar 清单里没有 Main-Class。应使用 java -cp "主jar:应用类" 主类 的方式运行,见第四章实测。

Q3:代码里 new DefaultExecutor() 编译出现 deprecation 警告? 1.6.0 起该无参构造器已弃用。实测警告为 [deprecation] DefaultExecutor() in DefaultExecutor has been deprecated。改用 DefaultExecutor.builder().setExecuteStreamHandler(...).get() 即可消除警告(本文全部示例已改用 builder)。

Q4:需要旧版本,但 downloads.apache.org 找不到? 官方主下载目录只保留最新版,实测旧版地址返回 404。历史版本在 https://archive.apache.org/dist/commons/exec/binaries/(实测返回 200),或直接从 Maven 中央仓库按版本号取 jar。

Q5:接入后运行报 NoClassDefFoundError 吗? Commons Exec 无运行期传递依赖,正常不会因缺依赖报错。若确实出现此类错误,请检查是否误把 test 作用域的 jar 当依赖,或类路径里混入了版本冲突的旧 jar。

九、参考链接

  1. Apache Commons Exec 官方主页:https://commons.apache.org/proper/commons-exec/
  2. 1.6.0 发行包下载:https://downloads.apache.org/commons/exec/binaries/commons-exec-1.6.0-bin.tar.gz
  3. 发行包 sha512 校验文件:https://downloads.apache.org/commons/exec/binaries/commons-exec-1.6.0-bin.tar.gz.sha512
  4. Maven 中央仓库 1.6.0 目录:https://repo1.maven.org/maven2/org/apache/commons/commons-exec/1.6.0/
  5. Apache 归档下载站(历史版本):https://archive.apache.org/dist/commons/exec/binaries/
  6. 官方 javadoc(1.6.0 在线 API 文档):https://commons.apache.org/proper/commons-exec/apidocs/
  7. Ubuntu JDK 17 包信息:https://packages.ubuntu.com/jammy/openjdk-17-jdk
  8. Maven 安装文档:https://maven.apache.org/install.html