APS 系列文章 08

JPMS 强封装:--add-opens 与快速失败

Java 9 引入模块系统(JPMS)后,跨模块访问 class 有了更强的封装约束。动态代理因为要在目标类所在的包内生成字节码,首当其冲。

APS 对这块的态度是:不硬来,快速失败并给出可操作的提示

类代理怎么定义类

类代理需要在目标类同一个包 里生成子类(这样才能访问包私有成员、合法 extends)。APS 用的是 MethodHandles.privateLookupIn 拿到目标类的私有 Lookup,再定义隐藏类。

当目标类在一个强封装模块 里时------任何没有 open 的包,包括 java.base 里的 java.util 这种------这个 private lookup 会被 JVM 拒绝。于是 proxy() 立刻失败,并抛出一条带 --add-opens 建议的异常。

一个真实报错

下面这段代码尝试代理 java.util.ArrayList

java 复制代码
try {
    AcceleratedProxy.proxy(ArrayList.class,
            (o, m, a) -> AcceleratedProxy.invokeSuper(o, m, a));
} catch (RuntimeException e) {
    System.out.println(e.getCause().getMessage());
}

输出:

text 复制代码
Cannot access java.util.ArrayList in module java.base (package java.util):
the package is not open to the unnamed module. Add --add-opens
java.base/java.util=ALL-UNNAMED to the JVM arguments, or declare
'opens java.util;' in the module's module-info.java.

这条消息把两件事都告诉你了:为什么失败 (包没 open),以及怎么修

两种修复方式

方式一:加 JVM 参数 (对 java.base 这种第三方模块常用):

bash 复制代码
java --add-opens java.base/java.util=ALL-UNNAMED ...

方式二:在目标模块声明 open(你自己的模块):

java 复制代码
module my.module {
    opens com.example.internal;   // 把包 open 出来
}

接口代理为什么不受影响

和类代理不同,接口代理用的是 public Lookup ,所以它只支持 public 接口------这和 java.lang.reflect.Proxy 的约束完全一致。非 public 接口代理则走 LookupManager,把生成类定义在接口自己的包里(上一篇讲过)。

所以「JPMS 强封装」这条限制,只针对类代理,接口代理不碰 private lookup。

设计上的取舍

值得点出来的是「快速失败」这个选择。很多库在这里会静默降级(比如偷偷换一个更慢但能工作的路径),结果是用户半年后才发现性能不对。APS 选择当场抛异常 + 明确提示 ,把决策权交给调用方------要么加 --add-opens,要么换接口代理。

这也呼应了本系列第一篇的核心观点:APS 的性能优势来自「直接 INVOKESPECIAL 调用父类方法」,而这要求代理类定义在目标类的包里。JPMS 的强封装直接堵死了这条路,所以必须显式 open,没有中间态。

小结

JPMS 强封装是类代理绕不开的一道坎。APS 的处理是:接口代理不受影响、类代理遇到强封装模块快速失败并给出 --add-opens 提示。理解这一点,你在模块化项目里就能提前规划好哪些包需要 open。

下一篇正式进入原理,回答那个贯穿全系列的问题:invokeSuper 到底是怎么变成 INVOKESPECIAL

本文示例代码见 aps-blog/examples,框架源码与完整文档见 APS 仓库

相关推荐
phltxy8 小时前
C语言操作符详解
java·c语言·算法
步行cgn9 小时前
@Configuration 详解:Spring 配置类的核心注解
java·后端·spring
sunshine22 girl9 小时前
Java学习一 环境配置2 安装和基本使用Idea
java·学习·intellij-idea
嘿嘿-6610 小时前
Windows 一键使用 GPT-6 Astra:Codex CLI 配置教程
java·人工智能·windows·gpt·chatgpt·web
策案案案11 小时前
YOLO: 将AI Agents嵌入到IntelliJ IDEA
java·大数据·人工智能·笔记·yolo·microsoft·intellij-idea
辰烨chenye13 小时前
LeetCode Hot 100 题解 · 堆篇
java·算法·leetcode
shehuiyuelaiyuehao13 小时前
算法29,前缀和,除自身以外的数组的乘积
java·数据结构·算法
小刘在重生~14 小时前
Java常用类|String类详解 + BigDecimal精准计算(含面试题)
java·开发语言·python
随遇而安zx14 小时前
【多线程】---JMM 与 volatile 深度解析
java·多线程