jpms通过强封装在编译期和运行时阻止对未导出包的访问,包括反射;仅导出接口包,隐藏实现类;配合requires依赖约束与类内private/final封装,实现双重防护。

Java 模块化系统(JPMS)通过强封装切断外部对核心算法实现的直接访问路径,不是靠“藏代码”,而是让非法访问在编译期就失败、运行时也无法绕过——哪怕用反射也进不去。
只导出接口,不导出实现类
模块必须明确声明哪些包对外可见。核心算法的逻辑类(如 AESImpl、SigningEngine)放在未导出的包里,仅把抽象接口或工厂方法所在包导出:
module com.example.crypto { exports com.example.crypto.api; }-
com.example.crypto.api.Encryptor是 public 接口,可被其他模块调用 -
com.example.crypto.internal.AES256Engine包未导出,即使类是 public,其他模块也无法 import 或 new 实例
反射也无法穿透模块边界
JPMS 的强封装是 JVM 层级的限制。从 Java 9 起,未导出的包默认禁止反射访问:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
Class.forName("com.example.crypto.internal.AES256Engine")会抛NoClassDefFoundError - 即使拿到类引用,
setAccessible(true)对其私有方法或字段也会失败,触发InaccessibleObjectException - 除非启动时加
--add-opens参数显式授权,否则无法突破
用模块依赖约束调用上下文
强封装配合 requires 和 requires transitive 可控制谁有权使用你的加密能力:
- 核心算法模块只
requires java.base,不依赖上层业务模块 - 业务模块需
requires com.example.crypto才能调用 API,但依然看不到内部类 - 若想让下游模块间接用到加密能力,用
requires transitive,但实现细节仍不暴露
结合语言封装做双重防护
模块边界是第一道墙,类内封装是第二道墙。即便某天模块配置出错,private + final + 不可变返回值仍能守住关键数据:
- 算法类内部密钥字段声明为
private final byte[] key; - 所有构造和初始化逻辑收在私有构造器或静态工厂中,杜绝非法状态
- 对外返回结果用不可变类型(如
ByteBuffer.asReadOnlyBuffer()),避免外部篡改中间态
不复杂但容易忽略:模块化强封装真正起效的前提,是开发者主动放弃“所有类都该能被调到”的惯性思维,把接口与实现像物理隔间一样切开。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










