解决Java模块化系统导致的ClassLoader.defineClass访问错误
本文最后更新于 2025-11-20,文章内容可能已经过时。
Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @119d7047
🧐 错误原因
——这是Java 9+版本中一个很常见的"模块化陷阱"。
这个错误是因为从Java 9开始引入的模块化系统(JPMS)对Java核心API的访问做了更严格的限制。简单来说:
你的代码(或Spring框架)试图通过反射访问ClassLoader.defineClass方法,但Java 9+默认禁止了这种访问,因为defineClass在java.base模块中是"protected final"的。
就像你试图进入一个受保护的房间,但没有获得许可一样。Java 9+的模块系统要求你必须显式"打开"这个包的访问权限。
🔧 解决方法
✅ 方法1:最简单直接的解决方案(推荐)
在启动参数中添加这个JVM参数:
--add-opens java.base/java.lang=ALL-UNNAMED
在IDEA中如何添加:
- 点击右上角的"Run" -> "Edit Configurations"
- 在"VM options"字段中添加:--add-opens java.base/java.lang=ALL-UNNAMED
- 点击"Apply",然后重新运行项目
在命令行中运行:
java --add-opens java.base/java.lang=ALL-UNNAMED -jar your-application.jar
✅ 方法2:升级Spring Boot版本(如果使用Spring)
如果你在使用Spring Boot,升级到2.3.0或更高版本(Spring官方已修复这个问题):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
</parent>
✅ 方法3:使用Spring的修正版cglib
如果你的项目依赖cglib,可以使用Spring提供的修正版:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.0</version> <!-- 或更高版本 -->
</dependency>
⚠️ 注意事项
- 这个解决方案不会影响应用功能,只是临时允许访问被限制的API
- 不要尝试"绕过"这个限制(比如修改JDK源码),这会带来安全风险
- 如果你使用的是Java 8,这个错误不会出现(因为Java 8没有模块系统)
💡 为什么会出现这个问题?
这个错误通常发生在以下场景:
- 你使用了CGLIB动态代理(比如Spring AOP)
- 你的项目使用了Java 9+版本
- 项目依赖的库(如Spring)试图通过反射访问ClassLoader.defineClass方法
就像我上次在项目中遇到的,当时我用CGLIB代理了一个没有实现接口的类,结果在Java 11上跑起来就报这个错误,加了那个JVM参数后就完美解决了。
🌟 小贴士
如果你是刚开始接触Java模块化,可以这样理解:
- Java 8及之前:没有模块系统,所有类都"开放"
- Java 9+:引入了模块系统,对核心API做了更严格的访问控制
- 解决方案:通过--add-opens参数"临时开放"特定包的访问
- 感谢你赐予我前进的力量

