Ubuntu 22.04 安装 Apache Commons Weaver 指南

在 Ubuntu 22.04 上安装 Apache Commons Weaver 2.0(JDK 8 构建期织入器),覆盖 apt 安装 JDK 8 与 Maven、Maven 插件依赖与官方 bin 包两种方案、privilizer 织入最小验证、JDK 17 兼容性实测结论与卸载清理,命令回显均实测通过。

Apache Commons WeaverApache Commons Weaver2026/10/15

Ubuntu 22.04 安装 Apache Commons Weaver 指南

目标:在 Ubuntu 22.04 上从零搭建 Apache Commons Weaver 2.0 的使用环境(JDK 8 + Maven 3.6.3),跑通 privilizer 织入提供者的最小验证工程,并给出官方 bin 包 + 手动 classpath 的离线方案;本文全部命令与回显均已在 Ubuntu 22.04 实测通过。

Apache Commons Weaver 是 Apache Commons 下的构建期字节码织入框架:它不是一个业务工具库,而是一套「扫描编译产物 class → 按注解改写字节码 → 写回」的处理器体系。官方内置两个织入提供者:privilizer(把标注 @Privileged 的方法体重写为 AccessController.doPrivileged 特权块)与 normalizer(把重复生成的匿名类收敛到规范位置)。它的「安装」本质是:装好 JDK 与构建工具 → 引入 processor/织入提供者模块 → 用 Maven 插件或命令行触发织入 → 用 javap 验证产物。特别地,Weaver 2.0 的织入器只能在 JDK 8 上运行(实测 JDK 17 直接报错,见第三章与 FAQ),本文按 JDK 8 编写全流程。

一、环境信息

本节先固定可复现的基线环境,后续所有命令均在此环境执行。

  • 操作系统:Ubuntu 22.04.5 LTS(PRETTY_NAME="Ubuntu 22.04.5 LTS")
  • 架构:x86_64
  • JDK:OpenJDK 1.8.0_504(apt 包 openjdk-8-jdk,织入器实测必须运行在 JDK 8)
  • 构建工具:Apache Maven 3.6.3(apt 包 maven)
  • 组件版本:Apache Commons Weaver 2.0(2018-09-07 发布)
  • Maven 坐标:org.apache.commons:commons-weaver-processor:2.0、org.apache.commons:commons-weaver-privilizer:2.0、org.apache.commons:commons-weaver-privilizer-api:2.0、org.apache.commons:commons-weaver-maven-plugin:2.0
  • 官方下载目录:https://downloads.apache.org/commons/weaver/
  • 验证用工作目录:/work/mini-demo(Maven 最小验证工程)、/work/planb(bin 包直跑)

系统与架构确认(实时回显):

cat /etc/os-release | head -3
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
uname -m
x86_64

💡 技术拓展:Java 生态里「给已有 class 增加能力」有三条主流路线,Weaver 属于构建期织入——

路线代表发生时机特点
构建期字节码织入Commons Weaver、AspectJ ajcjavac 编译之后、打包之前产物自包含,运行期零额外依赖
类加载期织入(LTW)AspectJ Weaver(-javaagent)JVM 加载 class 时不改构建流程,但需 agent 与 weaving classloader
运行期动态代理JDK Proxy / CGLIB程序运行时只能包装接口/可继承方法,无字节码改动

本文采用 Commons Weaver(构建期织入):织入在 mvn package 阶段完成,运行期 classpath 干净(实测织入产物运行无需携带任何 Weaver jar)。

二、前置条件

本节说明安装前必须满足的条件。

  1. 具有 root 或 sudo 权限的 Ubuntu 22.04 系统。
  2. 可访问 Ubuntu 官方软件源(apt update 能正常拉取索引)。
  3. 可访问 Maven 中央仓库 repo1.maven.org 与 Apache 官方下载站 downloads.apache.org(本文实测网络直连可达)。
  4. 至少 1 GB 可用磁盘空间(JDK 8 + Maven + 织入模块依赖合计约 400 MB)。

网络连通性确认(实时回显):

curl -sI --max-time 20 https://repo1.maven.org/maven2/org/apache/commons/commons-weaver-processor/2.0/ | head -1
HTTP/1.1 200 OK
curl -sI --max-time 20 https://downloads.apache.org/commons/weaver/ | head -1
HTTP/1.1 200 OK

三、版本选型说明

本节回答「装哪个版本、用哪个 JDK」。Commons Weaver 是典型的低频发布项目:官方下载目录 https://downloads.apache.org/commons/weaver/ 上只有 2.0 一个版本线,binaries/ 目录实测内容如下:

curl -s --max-time 30 https://downloads.apache.org/commons/weaver/binaries/ | grep -oE 'commons-weaver[^"<> ]*\.tar\.gz|commons-weaver[^"<> ]*\.zip' | sort -u
commons-weaver-2.0-bin.tar.gz
commons-weaver-2.0-bin.zip

RELEASE-NOTES.txt(2018-09-07)明确写着 "Requires Java 8 or greater",本版核心变更为升级 Java 8 基线(WEAVER-19)、xbean-finder 4.9(WEAVER-21)、ASM 6.2.1(WEAVER-22)、commons-parent v47(WEAVER-26)。2.0 之后官方未再发布新版本,维护处于停滞状态;但它的模块在 Maven 中央仓库全部可用且 API 稳定,生产使用需自行评估「低频维护」这一事实。

模块(中央仓库实测存在)作用是否必须
commons-weaver-processor:2.0织入处理器内核:扫描 class、按 SPI 加载提供者必须
commons-weaver-privilizer-api:2.0privilizer 注解(@Privileged/@Privilizing)privilizer 场景必须
commons-weaver-privilizer:2.0privilizer 织入提供者(重写特权块)privilizer 场景必须
commons-weaver-normalizer:2.0normalizer 织入提供者(收敛匿名类)可选
commons-weaver-maven-plugin:2.0Maven 插件(weave/prepare 等 goal)Maven 方案必须
commons-weaver-antlib:2.0Ant 任务可选

⚠️ 注意:社区资料里提到的 commons-weaver-proxy「动态代理织入提供者」在 2.0 发布物与 Maven 中央仓库中均不存在(https://repo1.maven.org/maven2/org/apache/commons/commons-weaver-proxy/2.0/ 返回 404,bin 包内亦无此 jar),不要按该名称引用。

JDK 兼容性实测结论(选型关键):织入器运行在哪个 JDK 上执行织入与产物跑在哪个 JRE 上是两回事:

环节JDK 8JDK 17
编译演示工程(产物字节码 major 52)通过通过
执行织入(commons-weaver:weave)通过失败
运行织入产物通过通过(字节码 major 52,JRE 向下兼容)

JDK 17 上织入的真实报错:

[ERROR] Failed to execute goal org.apache.commons:commons-weaver-maven-plugin:2.0:weave (default) on project privilizer-demo: weaving failed due to java.lang.IllegalStateException: java.lang.IllegalArgumentException: Unsupported class file major version 61 -> [Help 1]

根因:privilizer 织入时需要读取被调用方类文件(包括 JDK 自身的 java/lang/System 等)判断可访问性,其内嵌的 ASM 6.2.1(以 shaded 形式打包在 privilizer jar 内,无法通过替换依赖升级)不认识 JDK 17 的 major 61 字节码。因此执行织入的构建环境必须使用 JDK 8,本文按此编写。若希望构建期用 JDK 17、仅织入步骤用 JDK 8,可在 Maven 工具链中为 commons-weaver-maven-plugin 单独指定 JDK 8(toolchains.xml),本文不展开。

四、方案 A:Maven 依赖安装(在线,推荐)

本节通过 apt 安装 JDK 8 与 Maven,再用 Maven 坐标引入 Weaver 模块并跑通 privilizer 织入最小验证工程。

4.1 方案说明

方案 A 的链路是:apt 安装 openjdk-8-jdk 与 maven → 切换系统默认 JDK 到 8 → 工程 pom.xml 中声明 commons-weaver-privilizer-api(编译期注解)与 commons-weaver-maven-plugin(插件级依赖带入 privilizer 织入器)→ mvn package 时在 process-classes 阶段自动织入 → 运行验证。

4.2 安装 JDK 8 并切换默认版本

apt-get update && apt-get install -y openjdk-8-jdk
# 输出节选(实测首尾)
Setting up openjdk-8-jdk:amd64 (8u504-ga-1ubuntu1~22.04.3) ...

安装后确认版本与包信息:

apt-cache policy openjdk-8-jdk maven | grep -E 'openjdk-8-jdk:|maven:|Installed:' | head -4
openjdk-8-jdk:
  Installed: 8u504-ga-1ubuntu1~22.04.3
maven:
  Installed: 3.6.3-5

Ubuntu 22.04 上执行 apt install openjdk-8-jdk maven 后,系统默认 java 仍指向 OpenJDK 11(maven 会连带安装 default-jdk),必须切换 alternatives,否则织入时会遇到第三章的 major version 报错(JDK 11 字节码 major 55 同样不被 ASM 6.2.1 支持)。实测切换过程:

java -version 2>&1 | head -1
openjdk version "11.0.32.1" 2026-08-18
update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
update-alternatives --set javac /usr/lib/jvm/java-8-openjdk-amd64/bin/javac
java -version 2>&1
update-alternatives: using /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java to provide /usr/bin/java (java) in manual mode
openjdk version "1.8.0_504"
OpenJDK Runtime Environment (build 1.8.0_504-8u504-ga-1ubuntu1~22.04.3-b01)
OpenJDK 64-Bit Server VM (build 25.504-b01, mixed mode)

验证点:java -version 输出 1.8.0_504 且无 11.0.x,说明默认 JVM 已切到 JDK 8。

4.3 确认 Maven 绑定 JDK 8

mvn -v | head -3
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 1.8.0_504, vendor: Ubuntu, runtime: /usr/lib/jvm/java-8-openjdk-amd64/jre

验证点:Java version 一行显示 1.8.0_504,说明 Maven 已绑定 JDK 8(apt 版 Maven 经 PATH 中的 java 定位 JDK,alternatives 切换即生效,无需设置 JAVA_HOME)。

4.4 创建最小验证工程

创建工程目录:

mkdir -p /work/mini-demo/src/main/java/demo

/work/mini-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>weaver-mini</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-weaver-privilizer-api</artifactId>
      <version>2.0</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
      </plugin>
      <plugin>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-weaver-maven-plugin</artifactId>
        <version>2.0</version>
        <dependencies>
          <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-weaver-privilizer</artifactId>
            <version>2.0</version>
          </dependency>
        </dependencies>
        <configuration>
          <weaverConfig>
            <privilizer.policy>ALWAYS</privilizer.policy>
            <privilizer.accessLevel>public</privilizer.accessLevel>
          </weaverConfig>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>weave</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

逐项说明关键配置:

  • commons-weaver-privilizer-api:2.0:编译期注解来源(@Privileged),工程依赖声明一次即可。
  • 插件级 <dependencies> 中的 commons-weaver-privilizer:2.0:织入提供者必须挂在 commons-weaver-maven-plugin 的 <dependencies> 下。Weaver 插件通过 ServiceLoader 从插件自身的类加载空间发现织入提供者;若把它写成普通工程依赖,插件发现不了任何提供者,weave goal 会「成功」执行但一个类都不改(实测复现,详见 FAQ Q2)。
  • weaverConfig:织入参数键值对。privilizer.policy=ALWAYS 表示织入为无条件 doPrivileged 块;privilizer.accessLevel=public 允许 @Privileged 标注在 public 方法上(默认值 private,标注更宽访问级别的方法会直接报错,见 FAQ Q3)。
  • weave goal 默认绑定 process-classes 阶段,mvn package 自动触发。

4.5 最小验证代码

/work/mini-demo/src/main/java/demo/SecretStore.java(特权方法提供者):

package demo;

import org.apache.commons.weaver.privilizer.Privileged;

/**
 * 特权方法提供者:readToken 的方法体需要以特权方式读取系统属性。
 */
public final class SecretStore {

    private SecretStore() {
    }

    @Privileged
    public static String readToken() {
        return System.getProperty("demo.token", "unset");
    }
}

/work/mini-demo/src/main/java/demo/ConfigClient.java(普通调用方):

package demo;

/**
 * 普通调用方:直接调用特权方法,自身不做任何声明。
 */
public final class ConfigClient {

    private ConfigClient() {
    }

    public static String token() {
        return SecretStore.readToken();
    }
}

/work/mini-demo/src/main/java/demo/Main.java(入口):

package demo;

public final class Main {

    private Main() {
    }

    public static void main(String[] args) {
        System.out.println("ConfigClient.token()   = " + ConfigClient.token());
        System.out.println("SecurityManager active = " + (System.getSecurityManager() != null));
    }
}

4.6 构建织入与运行验证

cd /work/mini-demo && mvn -B clean package 2>&1 | grep -E 'weave|security leak|BUILD|Total time'
[INFO] --- commons-weaver:2.0:weave (default) @ weaver-mini ---
[WARNING] Possible security leak: granting privileges to public method demo/SecretStore.readToken()Ljava/lang/String;
[INFO] BUILD SUCCESS
[INFO] Total time:  0.974 s

回显解读:weave (default) 是织入 goal 在 process-classes 阶段执行;Possible security leak 警告来自 privilizer 自身的访问级别审计——它提醒「把特权授予 public 方法等于任何能调用该方法的人都获得特权」,属预期提示而非错误,介意可把 @Privileged 方法改为包级私有并把 privilizer.accessLevel 配回 private。

运行织入后的程序:

java -Ddemo.token=secret-123 -cp target/classes demo.Main
ConfigClient.token()   = secret-123
SecurityManager active = false

用 javap 验证织入确实发生(未织入的 readToken 只有一条 System.getProperty 调用):

javap -p -c target/classes/demo/SecretStore.class | grep -E 'readToken_ACTION|doPrivileged|__privileged'
       0: new           #34                 // class demo/SecretStore$readToken_ACTION
       4: invokespecial #36                 // Method demo/SecretStore$readToken_ACTION."<init>":()V
       7: invokestatic  #42                 // Method java/security/AccessController.doPrivileged:(Ljava/security/PrivilegedAction;)Ljava/lang/Object;
  static java.lang.String __privileged_access$0();
       0: invokestatic  #48                 // Method __privileged_readToken:()Ljava/lang/String;
  private static java.lang.String __privileged_readToken();

结果解读:原方法体被搬进合成方法 __privileged_readToken(),readToken() 本身被改写为「构造 SecretStore$readToken_ACTION 特权动作 → AccessController.doPrivileged 执行 → 强转返回」。这证明 privilizer 织入提供者在构建期真实生效,且运行产物不依赖任何 Weaver jar(-cp target/classes 即可运行)。

五、方案 B:官方 bin 包 + 手动 classpath 直跑(离线友好)

本节面向没有 Maven/构建体系的场景:下载官方 bin 包,用 javac/java 手动拼 classpath 完成编译、织入、运行。

5.1 方案说明

链路是:下载并校验 bin 包 → 解压得到 6 个 Weaver 模块 jar → 从中央仓库补齐 3 个传递依赖 jar(xbean-finder、xbean-asm6、commons-lang3)→ javac 编译演示源码 → 用一个 20 行的 WeaveRunner 类直调 WeaveProcessor 完成织入 → java 运行。适用于离线环境或想把织入嵌进自有构建脚本的读者。

5.2 下载与完整性校验

mkdir -p /work/planb && cd /work/planb
curl -sO --max-time 120 https://downloads.apache.org/commons/weaver/binaries/commons-weaver-2.0-bin.zip
curl -sO --max-time 60 https://downloads.apache.org/commons/weaver/binaries/commons-weaver-2.0-bin.zip.sha256
ls -l commons-weaver-2.0-bin.zip
cat commons-weaver-2.0-bin.zip.sha256
sha256sum commons-weaver-2.0-bin.zip
-rw-r--r-- 1 root root 2146159 Oct 15 03:02 commons-weaver-2.0-bin.zip
f5ec5a73d8b3a43b44b31e3e0eea9249d444214579dd649b03ad171b527603f2
f5ec5a73d8b3a43b44b31e3e0eea9249d444214579dd649b03ad171b527603f2  commons-weaver-2.0-bin.zip

验证点:.sha256 文件中的期望值与 sha256sum 实测值逐字一致;不一致必须删除重下。

5.3 解包与补齐传递依赖

cd /work/planb && unzip -q -o commons-weaver-2.0-bin.zip && ls commons-weaver-2.0/
LICENSE-asm6.2.1.txt
LICENSE.txt
NOTICE.txt
RELEASE-NOTES.txt
commons-weaver-antlib-2.0.jar
commons-weaver-maven-plugin-2.0.jar
commons-weaver-privilizer-2.0.jar
commons-weaver-privilizer-api-2.0.jar
commons-weaver-processor-2.0.jar
commons-weaver-normalizer-2.0.jar

💡 说明:bin 包只含 Weaver 自身 6 个模块 jar,不含织入器的传递依赖。命令行直跑还需从 Maven 中央仓库下载三个 jar:xbean-finder-shaded-4.9.jar、xbean-asm6-shaded-4.9.jar(注解扫描)与 commons-lang3-3.7.jar(processor 内部使用),本文已实测下载并验证可用:

cd /work/planb
M=https://repo1.maven.org/maven2
curl -sO --max-time 60 $M/org/apache/xbean/xbean-finder-shaded/4.9/xbean-finder-shaded-4.9.jar
curl -sO --max-time 60 $M/org/apache/xbean/xbean-asm6-shaded/4.9/xbean-asm6-shaded-4.9.jar
curl -sO --max-time 60 $M/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar

5.4 编写织入入口并编译演示源码

/work/planb/WeaveRunner.java(完整内容):

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.commons.weaver.WeaveProcessor;

public class WeaveRunner {

    public static void main(String[] args) throws Exception {
        final String target = args[0];
        final List<String> classpath = new ArrayList<>(java.util.Arrays.asList(args[1].split(":")));
        final Properties config = new Properties();
        config.setProperty("privilizer.policy", "ALWAYS");
        config.setProperty("privilizer.accessLevel", "public");
        new WeaveProcessor(classpath, new File(target), config).weave();
        System.out.println("WEAVE_DONE");
    }
}

准备演示源码(可直接复制 4.5 节三个类到 /work/planb/src/demo/),然后编译:

cd /work/planb && mkdir -p classes
R=commons-weaver-2.0
javac -encoding UTF-8 -cp $R/commons-weaver-privilizer-api-2.0.jar -d classes src/demo/*.java
javac -encoding UTF-8 -cp $R/commons-weaver-processor-2.0.jar:$R/commons-weaver-privilizer-2.0.jar -d classes WeaveRunner.java
JAVAC_OK

⚠️ 注意:javac 不带 -encoding UTF-8 时,源码中的中文注释在默认 POSIX locale 下会报 error: unmappable character for encoding ASCII(本文实测复现过 69 errors),这是编码问题不是语法问题,加参数即可解决。

5.5 执行织入并运行

织入器 classpath 由 6 个 jar 组成(3 个 Weaver 模块 + 3 个传递依赖):

cd /work/planb
R=commons-weaver-2.0
WC=$R/commons-weaver-processor-2.0.jar:$R/commons-weaver-privilizer-2.0.jar:$R/commons-weaver-privilizer-api-2.0.jar:xbean-finder-shaded-4.9.jar:xbean-asm6-shaded-4.9.jar:commons-lang3-3.7.jar
java -cp classes:$WC WeaveRunner /work/planb/classes $WC 2>&1 | grep -E 'PROVIDER|WARNING|WEAVE_DONE' | head -5
PROVIDER: org.apache.commons.weaver.privilizer.PrivilizerWeaver
WARNING: Possible security leak: granting privileges to public method demo/SecretStore.readToken()Ljava/lang/String;
WEAVE_DONE

回显解读:PROVIDER 一行说明 ServiceLoader 从 classpath 发现了 privilizer 织入提供者(bin 包 jar 内的 META-INF/services/org.apache.commons.weaver.spi.Weaver 注册文件生效);WEAVE_DONE 表示织入完成。

运行织入产物(运行期 classpath 只有 classes,无任何 Weaver jar):

java -Ddemo.token=secret-123 -cp /work/planb/classes demo.Main
ConfigClient.token()   = secret-123
SecurityManager active = false

验证点:与方案 A 结果一致,证明方案 A/B 只是织入的触发方式不同,产物等价。

六、方案对比与选择建议

维度方案 A:Maven 插件方案 B:bin 包 + 手动 classpath
织入触发process-classes 阶段自动执行自行调用 WeaveProcessor.weave()
依赖管理Maven 自动解析(含传递依赖)手工收集 3 个传递依赖 jar
与构建集成无缝,mvn package 一步到位需自写脚本拼 classpath
离线可用性首次需联网下载依赖下载完成后完全离线
适用场景常规工程开发(推荐)无构建体系环境、脚本化定制织入

选型建议:有 Maven/Gradle 构建体系一律选方案 A(Gradle 可用 Ant 任务 commons-weaver-antlib 桥接,本文不展开);把织入嵌入自研打包流水线时选方案 B,WeaveRunner 的三个入参(目标目录、classpath、织入配置)足够脚本化。

七、配置说明

Weaver 没有独立配置文件,全部配置通过 Maven 插件的 weaverConfig(Properties 键值对)或 WeaveProcessor 构造参数传入。实测有效的配置键:

配置键取值说明
privilizer.policyNEVER / ON_INIT / DYNAMIC(默认) / ALWAYSALWAYS 织入为无条件 doPrivileged;DYNAMIC 每次 @Privileged 方法执行时检查是否安装了 SecurityManager 再决定;ON_INIT 只在初始化时检查一次;NEVER 关闭织入
privilizer.accessLevelpublic / protected / package / private(默认)允许 @Privileged 标注的最大访问级别,超出即报错
privilizer.verifytrue / false织入后是否用 ASM 的 CheckClassAdapter 校验产物字节码(取自模块源码,本文未单独实测该开关)
normalizer.targetPackage合法包名normalizer 把合格匿名类重映射到该包下的 $normalized<摘要> 规范位置

环境变量方面,apt 安装的 Maven 经 PATH 中的 java(alternatives 指向 JDK 8)定位 JDK,实测 JAVA_HOME 为空也能构建;若机器上有多套 JDK 且希望显式固定,可导出:

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 && echo "JAVA_HOME=$JAVA_HOME"
JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

八、常见问题(FAQ)

Q1:织入时报 Unsupported class file major version 61 怎么办? 这是在 JDK 17(或 11)上执行 weave 的典型报错:privilizer 判断方法可访问性时要读取 JDK 自身类文件,内嵌的 ASM 6.2.1 只支持到 Java 8 时代的字节码(major 52),遇到 major 61 即抛错。解法:把执行织入的构建环境换成 JDK 8(update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java 切换后用 mvn -v 确认 Java version: 1.8.0_xxx)。注意产物字节码是 major 52,JDK 17 的 JRE 仍可运行,所以「构建用 8、运行用 17」在字节码层面是可行的,但 privilizer 的安全语义依赖 SecurityManager,而 SecurityManager 自 JDK 17 起已标记废弃,长期规划请参考官方 JEP 411 的迁移指引。

Q2:mvn package 显示 BUILD SUCCESS 但 javap 发现类根本没被织入? 最常见原因:把 commons-weaver-privilizer 写成了普通工程依赖。Weaver 插件通过 ServiceLoader 从插件自身的类加载空间发现织入提供者,工程依赖进入不了这个空间,于是 weave goal 静默空转。解法:把该依赖挪到插件级 <dependencies>(见 4.4 节 pom),重跑 mvn clean package。

Q3:报 must have maximum access level 'private' but is defined wider ('public')? @Privileged 默认只允许标注 private 方法,标注在 public/protected 方法上且未放宽配置时织入失败。解法:weaverConfig 增加 <privilizer.accessLevel>public</privilizer.accessLevel>。放宽后织入会输出 Possible security leak 警告——这是有意的安全提示,评估接受即可。

Q4:javac 报大量 unmappable character for encoding ASCII? POSIX locale 下 javac 默认按 ASCII 解码源码,中文注释必报错。解法:javac -encoding UTF-8;Maven 工程则确认 pom 里有 project.build.sourceEncoding=UTF-8。

Q5:运行时想验证特权块真的生效,为什么加了 -Djava.security.manager 还是没差别? SecurityManager 默认策略下不会拒绝普通代码读系统属性,需要配合自定义 policy 限制调用方权限才能观察到「织入前 AccessControlException、织入后正常返回」的差异。完整对照实验(分离 codeSource + policy 文件 + 前后栈回显)见《Apache Commons Weaver 2.0 织入示例与最佳实践详解》第三章。

Q6:可以用 -javaagent 在运行期织入吗? 不可以。Commons Weaver 2.0 只提供构建期织入,官方发布物中没有 Java agent jar,-javaagent 方式无从谈起。需要类加载期织入请评估 AspectJ LTW 等方案(对比见第一章技术拓展表)。

九、卸载与清理

移除验证工程与下载产物:

rm -rf /work/mini-demo /work/planb
ls /work/mini-demo 2>&1
ls: cannot access '/work/mini-demo': No such file or directory

清理 Maven 本地仓库中的 Weaver 模块(影响所有工程,慎用):

rm -rf $HOME/.m2/repository/org/apache/commons/commons-weaver-*

卸载 JDK 8 与 Maven(仅当不再需要,先 -s 预演确认):

apt-get -s purge -y openjdk-8-jdk maven | grep -E 'REMOVED|Purg' | head -4
The following packages will be REMOVED:
  maven* openjdk-8-jdk*
Purg maven [3.6.3-5]
Purg openjdk-8-jdk [8u504-ga-1ubuntu1~22.04.3]

确认无误后真正卸载:

apt-get purge -y openjdk-8-jdk maven && apt-get autoremove -y

十、参考链接

  1. Apache Commons Weaver 官方主页:https://commons.apache.org/proper/commons-weaver/
  2. Apache Commons Weaver 官方下载目录:https://downloads.apache.org/commons/weaver/
  3. Commons Weaver 2.0 发布说明:https://downloads.apache.org/commons/weaver/RELEASE-NOTES.txt
  4. Maven 中央仓库坐标页:https://repo1.maven.org/maven2/org/apache/commons/commons-weaver-processor/
  5. Weaver Maven 插件文档:https://commons.apache.org/proper/commons-weaver/commons-weaver-maven-plugin/
  6. OpenJDK 8 安装包(Ubuntu 官方源):apt-cache show openjdk-8-jdk