IllegalAccessError在Java 9+模块化环境中是运行时模块访问控制失败所致,非编译问题;需检查exports/opens声明、JVM参数--add-opens及依赖模块是否适配JPMS。
遇到 illegalaccesserror,尤其在 java 9+ 模块化(jpms)环境下,**不是编译失败,而是运行时模块访问控制被拦截**。它和 illegalaccessexception 不同:后者是反射调用时抛出的受检异常,而前者是 jvm 在解析类、字段或方法引用时,发现违反模块可访问性规则(比如跨模块访问非导出包里的 public 类,或反射操作未开放的包),直接中断执行的致命错误。
看堆栈,确认是不是模块系统惹的祸
以下情况高度提示问题出在模块系统:
- 异常信息里出现
module not exported、not open to module、jdk.internal.module.Modules或java.lang.Module - 项目有
module-info.java,但报错类来自另一个模块(尤其是旧库没适配 JPMS) - 代码用了反射(如
field.setAccessible(true)、Class.getDeclaredMethod())去访问其他模块的包私有或 private 成员 - 报错涉及 JDK 内部类(如
sun.misc.Unsafe、java.util.ArrayList的内部实现)
查 module-info.java,补全 exports 和 opens
exports 和 opens 是两个不同作用的声明,不能互相替代:
-
exports com.example.api;:只允许其他模块“正常使用”这个包里的
public类和成员(new、调用 public 方法等)。它不管反射,也不让非 public 成员可见。 -
opens com.example.model;:专为反射开绿灯,允许其他模块通过反射读写该包内所有类的
private、package-private字段和方法。不影响编译期引用,也不暴露类给其他模块直接使用。 - 如果框架(Spring、Jackson、Hibernate)要注入或序列化你的类,且字段不是 public,就必须
opens;若只是提供 API 被调用,exports就够了。 - 慎用无限制 opens:
opens com.example.model;对所有模块开放;更安全的是定向开放:opens com.example.config to spring.core, com.fasterxml.jackson.databind;
盯紧 JDK 内部 API 和第三方库兼容性
很多 IllegalAccessError 实际上是旧库试图访问被强封装的 JDK 内部类(如 java.base/java.lang、java.base/java.util):
将 WCAG 2 AA 无障碍标准应用于设计系统、UI 组件和网页——通过可运行的验证器进行对比度计算,采用设计 token 模式使颜色天生可访问,设定排版和焦点状态规则,并提供语义检查清单。适用于构建或审查 UI。
- 先从堆栈里提取完整路径,例如报错提到
java.util.ArrayList,通常要开放的是java.base/java.util,不是java.util单独存在 - 临时方案:启动参数加
--add-opens java.base/java.util=ALL-UNNAMED(注意必须放在-jar前) - 长期方案:升级出问题的依赖。比如 Lombok 需要 1.18.30+ 才完全支持 JDK 21,Spring Boot 3.x 要求 Hibernate 6+,老版本 Hadoop 容易和新 JDK 的模块边界冲突
- 检查自动模块(Automatic Module):未声明
module-info.class的 JAR 默认变成 unnamed module,它无法访问你显式导出的包。用jdeps --list-deps your-app.jar查依赖图,识别 unnamed 模块
排除类加载器冲突与版本混用
模块系统之外,IllegalAccessError 也可能源于类加载机制问题:
- OSGi 或 Spring Boot DevTools 等环境容易出现多个 ClassLoader 加载同一类(如
ConstructorAccessorImpl),导致子类找不到父类定义——用 VisualVM 或jcmd <pid> VM.native_memory summary</pid>辅助定位 - Maven 多版本共存:执行
mvn dependency:tree | grep hadoop或grep grpc,确认没有不同版本的相同库同时引入;用<exclusions></exclusions>清理传递依赖 - JDK 编译 vs 运行不一致:确保
javac和java版本一致(特别是从 JDK 17 升到 21 后,--illegal-access=deny已成默认,不再容忍隐式反射)










