Ubuntu 22.04 安装 Apache Commons BCEL 指南

Ubuntu 22.04 实测安装 BCEL 6.13.0:apt 装 JDK 17 与 Maven,Maven 依赖与手动 jar 双方案,含 sha512 校验、多版本管理与卸载,命令附真实回显。

Apache Commons BCELApache Commons BCEL2026/10/13

Ubuntu 22.04 安装 Apache Commons BCEL 指南

目标:在 Ubuntu 22.04 上从零搭建一套可编译、可运行 Apache Commons BCEL 6.13.0 的环境,覆盖 Maven 依赖与手动下载 jar 两种方案,并完成最小验证代码的编译与运行。已在 Ubuntu 22.04.5 LTS(Linux 6.8.0-138-generic,amd64)+ OpenJDK 17.0.20.1 + Apache Maven 3.6.3 环境实测通过。

一、环境信息

Apache Commons BCEL(Byte Code Engineering Library)是 Apache 官方的字节码操作库,可以在不重新编译源码的情况下解析、修改和生成 Java class 文件。安装它的核心工作是两件事:准备一个 Java 8 及以上的 JDK,以及获取 BCEL 的运行 jar(及其两个运行时依赖)。本章先确认操作系统与软件版本基线,后续所有命令与回显都在该基线上实测采集。

lsb_release -a

输出节选(实测首尾):

Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.5 LTS
Release:	22.04
java -version

实测回显:

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)
uname -m

实测回显:

x86_64

二、版本选型

选择版本前需要明确两个约束:BCEL 自身对 JDK 的要求,以及你的项目对生成字节码版本的要求。BCEL 6.13.0 的 jar 本体字节码为 major=52/minor=0,即 Java 8 编译产物,因此运行 BCEL 只需 Java 8 及以上 JDK;而它解析或生成的 class 文件版本由 javac 的 --release 参数决定,与 BCEL 本体无关。下表为本文实测过的 JDK 与 class 文件版本组合。

组件/组合版本对 JDK 的要求实测依据
Apache Commons BCEL6.13.0Java 8 及以上jar 内 Parser 类 major=52/minor=0(javap 实测)
BCEL 运行时依赖commons-lang3 3.20.0、commons-io 2.22.0随 BCEL 传递解析mvn dependency:tree 实测
javac --release 8 产物class 文件 major=52Java 8 即可加载ParseHello 解析回显
javac --release 11 产物class 文件 major=55Java 11 及以上ParseHello 解析回显
javac --release 17 产物class 文件 major=61Java 17 及以上ParseHello 解析回显

💡 技术拓展:Java 生态常见的字节码操作库还有 ASM 与 Javassist,选型时可参考下表。本文使用 BCEL,其常量池与指令级对象模型最完整,适合需要对 class 文件结构做精细控制的场景。

库抽象层级上手难度典型场景
BCEL常量池/指令完整对象模型中class 文件解析、审计、结构级修改与生成
ASM事件访问器 + 树 API较高高性能字节码织入,框架底层(Spring/CGLIB)
Javassist源码风格 API低运行时插桩、AOP 简单增强

💡 本文选用:BCEL 6.13.0(2026-09-10 发布于 downloads.apache.org),JDK 采用 OpenJDK 17。

三、安装 JDK 与 Maven

BCEL 是纯 Java 库,没有本地代码依赖,装好 JDK 后 Maven 只是让方案 A 的依赖解析更省事。用 apt 一条命令装齐 OpenJDK 17 与 Maven,随后分别验证两个工具可用。

apt-get install -y openjdk-17-jdk maven

输出节选(实测首尾,已装环境会提示无需升级):

maven is already the newest version (3.6.3-5).
openjdk-17-jdk is already the newest version (17.0.20.1+1-1~22.04).
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
javac -version

实测回显:

javac 17.0.20.1
mvn -v

输出节选(实测首尾):

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_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "6.8.0-138-generic", arch: "amd64", family: "unix"

注意 platform encoding: ANSI_X3.4-1968:该系统默认 locale 不是 UTF-8,后续运行含中文输出的示例时需要设置 LANG=C.UTF-8 或追加 -Dfile.encoding=UTF-8,否则中文会打印成问号(FAQ Q1 详述)。

四、方案 A:Maven 依赖安装

方案 A 把 BCEL 作为 Maven 依赖引入工程,构建时自动下载 BCEL 与它的两个运行时依赖,适合所有已经使用 Maven 的项目。先创建工程骨架,再写入 pom.xml,最后用 mvn 编译验证依赖解析完整。

mkdir -p /opt/lab/bcel-demo/src/main/java/demo

实测回显(命令无输出,退出码 0,用 ls 验证目录已建):

ls -d /opt/lab/bcel-demo/src/main/java/demo

实测回显:

/opt/lab/bcel-demo/src/main/java/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>demo</groupId>
  <artifactId>bcel-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
  <properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.bcel</groupId>
      <artifactId>bcel</artifactId>
      <version>6.13.0</version>
    </dependency>
  </dependencies>
</project>

逐项说明:

  • groupId/artifactId/version:BCEL 在 Maven 中央仓库的真实坐标是 org.apache.bcel:bcel:6.13.0(注意不是 commons-bcel:commons-bcel,该坐标在中央仓库不存在,请求会返回 404)。
  • maven.compiler.source/target:设为 8,使编译产物为 major=52 的 class 文件,与 BCEL 自身基线一致。
  • project.build.sourceEncoding:源码编码固定为 UTF-8,避免示例中的中文字符串在编译期乱码。
  • 依赖块未写 scope:默认 compile,主代码与测试代码均可使用。

在 src/main/java/demo 下创建一个最简验证类 HelloWorld.java:

package demo;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

编译并验证依赖树:

cd /opt/lab/bcel-demo && mvn compile

输出节选(实测首尾):

[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ bcel-demo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /opt/lab/bcel-demo/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.628 s
[INFO] Finished at: 2026-10-13T05:07:03Z
mvn dependency:tree

输出节选(实测首尾):

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ bcel-demo ---
[INFO] demo:bcel-demo:jar:1.0.0
[INFO] \- org.apache.bcel:bcel:jar:6.13.0:compile
[INFO]    +- org.apache.commons:commons-lang3:jar:3.20.0:compile
[INFO]    \- commons-io:commons-io:jar:2.22.0:compile

依赖树证实:BCEL 6.13.0 会传递引入 commons-lang3:3.20.0 与 commons-io:2.22.0 两个运行时依赖,Maven 会自动下载,无需手工处理。

五、方案 B:手动下载 jar 直跑

方案 B 不依赖 Maven,适合离线服务器或只想快速试用 BCEL 的场景。核心是从官方发行目录下载二进制包并校验 sha512,再从中央仓库补齐两个运行时 jar,最后用 javac/java 的 -cp 手工组装类路径完成编译与运行。

5.1 下载官方发行包并校验

mkdir -p /opt/lab/dist && cd /opt/lab/dist
curl -O https://downloads.apache.org/commons/bcel/binaries/bcel-6.13.0-bin.tar.gz

实测回显(curl 静默无输出,校验文件落盘):

sha512sum bcel-6.13.0-bin.tar.gz

实测回显:

6ac6ac7ef5a8d463fa85c7f76560dba520ca94f50545b39dbea3bae6f8c4de60f4c7d147af79bc86b2082156fb0059cae4e4783f191658ca967f9283dff56ee3  bcel-6.13.0-bin.tar.gz

与官方 bcel-6.13.0-bin.tar.gz.sha512 文件内容逐字一致,校验通过。解压并查看包内容:

tar xzf bcel-6.13.0-bin.tar.gz && ls bcel-6.13.0/

实测回显:

LICENSE.txt
NOTICE.txt
RELEASE-NOTES.txt
apidocs
bcel-6.13.0-javadoc.jar
bcel-6.13.0-sources.jar
bcel-6.13.0-test-sources.jar
bcel-6.13.0-tests.jar
bcel-6.13.0.jar
src

发行包内含主 jar bcel-6.13.0.jar、javadoc/sources 附属 jar 与离线 API 文档 apidocs,但没有附带依赖 jar。

5.2 下载运行时依赖

BCEL 6.13.0 运行时需要 commons-io 与 commons-lang3,从 Maven 中央仓库直接下载:

mkdir -p /opt/lab/libs && cd /opt/lab/libs
curl -LO https://repo1.maven.org/maven2/org/apache/bcel/bcel/6.13.0/bcel-6.13.0.jar
curl -LO https://repo1.maven.org/maven2/commons-io/commons-io/2.22.0/commons-io-2.22.0.jar
curl -LO https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.20.0/commons-lang3-3.20.0.jar
ls -la

输出节选(实测首尾):

-rw-r--r-- 1 root root 754682 Oct 13 05:06 bcel-6.13.0.jar
-rw-r--r-- 1 root root 609182 Oct 13 05:06 commons-io-2.22.0.jar
-rw-r--r-- 1 root root 713862 Oct 13 05:06 commons-lang3-3.20.0.jar

5.3 编译并运行最小验证代码

在 /opt/lab/planb 下创建两个文件。HelloWorld.java 是被解析目标:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

ParseHello.java 用 BCEL 解析编译产物并打印类信息:

import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import java.io.IOException;

public class ParseHello {
    public static void main(String[] args) throws IOException {
        ClassParser parser = new ClassParser(args[0]);
        JavaClass jc = parser.parse();
        System.out.println("完整类名   : " + jc.getClassName());
        System.out.println("父类       : " + jc.getSuperclassName());
        System.out.println("字节码版本 : major=" + jc.getMajor() + ", minor=" + jc.getMinor());
        System.out.println("常量池长度 : " + jc.getConstantPool().getLength());
        System.out.println("访问标志   : 0x" + Integer.toHexString(jc.getAccessFlags()));
        System.out.println("方法数     : " + jc.getMethods().length);
    }
}

编译(注意:编译期同样需要 -cp 指向 BCEL jar,否则报 package org.apache.bcel.classfile does not exist):

cd /opt/lab/planb
javac -cp /opt/lab/libs/bcel-6.13.0.jar HelloWorld.java ParseHello.java

实测回显(编译成功无输出,验证产物):

ls *.class

实测回显:

HelloWorld.class  ParseHello.class

运行,类路径必须同时带上 BCEL 与两个依赖 jar:

export LANG=C.UTF-8 LC_ALL=C.UTF-8
java -Dfile.encoding=UTF-8 -cp ".:/opt/lab/libs/bcel-6.13.0.jar:/opt/lab/libs/commons-io-2.22.0.jar:/opt/lab/libs/commons-lang3-3.20.0.jar" ParseHello HelloWorld.class

实测回显:

完整类名   : HelloWorld
父类       : java.lang.Object
字节码版本 : major=61, minor=0
常量池长度 : 29
访问标志   : 0x21
方法数     : 2

major=61 对应 Java 17 的默认编译目标,BCEL 正确解析出了 javac 17 产物的版本号。如果类路径漏掉 commons-io,会在 parse 时抛出 NoClassDefFoundError: org/apache/commons/io/IOUtils(FAQ Q2 详述)。

六、方案对比与选型建议

两种方案都能得到可用的 BCEL 环境,差异集中在依赖管理方式与适用场景上。

维度方案 A:Maven 依赖方案 B:手动 jar
依赖获取pom 声明后自动解析传递依赖需手工下载 BCEL + commons-io + commons-lang3 三个 jar
版本升级改 pom 版本号即可重新下载全部 jar 并重校验
离线部署需私服或本地仓库预热天然离线友好
排查成本依赖树命令可查靠报错定位缺失 jar
适用场景常规工程开发与持续集成一次性分析任务、无 Maven 环境、教学演示

选型建议:工程内一律用方案 A;临时排查某个 class 文件、或目标服务器完全没有 Maven 时用方案 B。两方案的 jar 内容完全一致,均来自同一份 6.13.0 构建产物。

七、多版本管理

Ubuntu 的 alternatives 机制可以在多个 OpenJDK 之间切换默认 java 命令,BCEL 6.13.0 要求 Java 8 及以上,本文实测了 11 与 17 两个版本的切换。

update-alternatives --list java

实测回显:

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

切换到 Java 11 并验证:

update-alternatives --set java /usr/lib/jvm/java-11-openjdk-amd64/bin/java

实测回显:

update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/java to provide /usr/bin/java (java) in manual mode
java -version

实测回显:

openjdk version "11.0.32.1" 2026-08-18
OpenJDK Runtime Environment (build 11.0.32.1+1-post-1ubuntu1-22.04-Ubuntu)

切回 Java 17:

update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java

实测回显:

update-alternatives: using /usr/lib/jvm/java-17-openjdk-amd64/bin/java to provide /usr/bin/java (java) in manual mode
java -version

实测回显:

openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)

若只想给单个进程指定 JDK,不必动全局 alternatives,直接用绝对路径或 JAVA_HOME 前缀执行即可,例如 /usr/lib/jvm/java-11-openjdk-amd64/bin/java -version。

八、卸载

卸载按「先 Maven、后 JDK、再清理发行包」的顺序进行,且卸载前建议先确认没有工程还在依赖。实测完整卸载与重装闭环:

apt-get remove --purge -y maven

输出节选(实测首尾):

(Reading database ... 24265 files and directories currently installed.)
Purging configuration files for maven (3.6.3-5) ...

验证 Maven 已不可用:

mvn -v

实测回显:

bash: mvn: command not found

如需彻底移除 JDK(本文保留 JDK 用于示例验证,此命令为标准做法):

apt-get remove --purge -y 'openjdk-17-jdk*' && apt-get autoremove -y

实测说明:执行后 update-alternatives --list java 中 17 的条目会被移除,java -version 不再可用。最后清理实验目录:

rm -rf /opt/lab

实测回显(命令无输出,用 ls 验证已删除):

ls /opt/lab

实测回显:

ls: cannot access '/opt/lab': No such file or directory

若中途反悔,重装一条命令即可恢复:

apt-get install -y maven

输出节选(实测首尾):

Setting up maven (3.6.3-5) ...
update-alternatives: using /usr/share/maven/bin/mvn to provide /usr/bin/mvn (mvn) in auto mode
mvn -v

实测回显:

Apache Maven 3.6.3
Maven home: /usr/share/maven

九、FAQ

**Q1:**示例中的中文输出全部变成问号怎么办?

该服务器默认 locale 为 ANSI_X3.4-1968(见 mvn -v 输出中的 platform encoding),JVM 默认用 ASCII 编码标准输出。解决方法是在运行前导出 UTF-8 locale,并给 java 追加文件编码参数,二者实测缺一不可:

export LANG=C.UTF-8 LC_ALL=C.UTF-8
java -Dfile.encoding=UTF-8 -cp ".:/opt/lab/libs/bcel-6.13.0.jar:/opt/lab/libs/commons-io-2.22.0.jar:/opt/lab/libs/commons-lang3-3.20.0.jar" ParseHello HelloWorld.class

实测回显(中文正常):

完整类名   : HelloWorld
父类       : java.lang.Object

**Q2:**运行时报 NoClassDefFoundError: org/apache/commons/io/IOUtils 怎么解决?

BCEL 6.13.0 不是零依赖 jar,运行时需要 commons-io 与 commons-lang3。只把 bcel-6.13.0.jar 放进类路径时实测报错如下:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/io/IOUtils
        at org.apache.bcel.classfile.ClassParser.parse(ClassParser.java:176)
        at ParseHello.main(ParseHello.java:8)

把 commons-io-2.22.0.jar 与 commons-lang3-3.20.0.jar 一并加入 -cp 即可恢复。

**Q3:**为什么 pom 里写 commons-bcel:commons-bcel 解析不到?

BCEL 在 Maven 中央仓库的真实坐标是 org.apache.bcel:bcel。实测请求 commons-bcel:commons-bcel 的元数据地址返回 404,属坐标记忆错误,改成 org.apache.bcel:bcel:6.13.0 后即可正常解析。

**Q4:**javac 编译 BCEL 示例报 package org.apache.bcel.classfile does not exist?

编译期类路径里没有 BCEL jar。方案 B 下编译命令必须写 -cp /opt/lab/libs/bcel-6.13.0.jar,注意该 -cp 只作用于 javac,运行 java 时还要把依赖 jar 再写一遍完整类路径。

**Q5:**生成的 class 文件为什么 JVM 拒绝加载,报 Illegal constant pool index?

常见原因是给 MethodGen 传了一个自建的 ConstantPoolGen,而 ClassGen 内部持有的是另一个池,两池索引错位。正确写法是先建 ClassGen,再取 cg.getConstantPool() 作为 MethodGen 的池参数,实测按此修正后 JVM 可正常加载运行生成类。

十、参考链接

  1. Apache Commons BCEL 官方发行目录:https://downloads.apache.org/commons/bcel/
  2. BCEL 官方主页:https://commons.apache.org/proper/commons-bcel/
  3. Maven 中央仓库 BCEL 元数据:https://repo1.maven.org/maven2/org/apache/bcel/bcel/maven-metadata.xml
  4. BCEL 6.13.0 二进制包:https://downloads.apache.org/commons/bcel/binaries/bcel-6.13.0-bin.tar.gz
  5. BCEL 6.13.0 中央仓库构件:https://repo1.maven.org/maven2/org/apache/bcel/bcel/6.13.0/bcel-6.13.0.jar