本文最后更新于 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中如何添加:

  1. 点击右上角的"Run" -> "Edit Configurations"
  2. 在"VM options"字段中添加:--add-opens java.base/java.lang=ALL-UNNAMED
  3. 点击"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参数"临时开放"特定包的访问