首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >[Java]add-open的使用及常见问题解决

[Java]add-open的使用及常见问题解决

作者头像
master336
发布2026-06-15 19:57:01
发布2026-06-15 19:57:01
50
举报

背景

在使用jdk17启动CMAK3.0.0.5/3.0.06版本时,页面显示异常,报如下错误信息: Caused by: java.lang.IllegalAccessError: class play.utils.Resources$ (in unnamed module @0x388ffbc2) cannot access class sun.net.www.protocol.file.FileURLConnection (in module java.base) because module java.base does not export sun.net.www.protocol.file to unnamed module

问题分析

报错信息指出了问题是无法访问sun.net.www.protocol.file.FileURLConnection类,java.base模块未设置该类所在包对所有未命名模块的访问 如此以来问题就定位在java.base的声明上

参数说明: –add-opens是Java 9及更高版本中引入的一个JVM启动参数,用于在Java模块化系统中开放特定模块的访问权限。这允许其他模块通过反射访问原本由于模块化限制而不可访问的类、方法或字段。 java.base: Java平台的核心模块,包含了Java语言的基础类。 基本语法

代码语言:javascript
复制
--add-opens <module>/<package>=<target-module>  

使用示例

代码语言:javascript
复制
 --add-opens java.base/java.lang=ALL-UNNAMED  

ALL-UNNAMED: 表示对所有未命名模块开放访问权限。未命名模块是指那些在模块路径(module-path)上但没有声明模块的JAR文件。

代码语言:javascript
复制
--add-opens java.base/java.lang=spring.core  

spring.core: 对Spring框架开放

问题解决

通过jvm add-opens参数来声明,示例如下

代码语言:javascript
复制
#要添加的参数
--add-opens java.base/sun.net.www.protocol.file=ALL-UNNAMED

完整的java启动命令示例如下(多个包需要放开访问示例)

代码语言:javascript
复制
java --add-opens java.base/sun.net.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.file=ALL-UNNAMED -Duser.dir=/data -cp xxx.jar xxx

如下内容仅为参考======================

附录

    1. 扩展知识(基于GPT-4总结) –add-opens 是 Java 模块化系统(模块化系统就是 Jigsaw 项目)中的一个 JVM 启动参数,它主要用来解决由于模块化机制引入的模块边界封装限制问题。该参数允许我们在运行应用程序时,临时打开一个模块的指定包,使其可以被未声明的模块访问。

自从 Java 9 引入模块化(即 Jigsaw 项目)后,为了增强安全性和封装性,模块不再像以前那样允许任意访问所有模块和包中的内容。Java 模块机制通过模块之间的依赖和导出规则来限制访问,具体体现在以下两点:

  1. 模块需要导出(exports)某个包,其他模块才能直接访问其中的公共类和成员。
  2. 反射(如 setAccessible(true))不能再随意突破模块化边界对内部非公开成员进行访问,除非显式允许该行为。 在很多情况下,某些库(如 Spring、Hibernate 等)依赖反射机制访问非公开的类或成员,因此会因为封装限制导致程序运行失败。–add-opens 参数就是为了解决这种问题。

语法

代码语言:javascript
复制
--add-opens <模块名称>/<包名称>=<目标模块>  
  • <模块名称>:开放该包所属的模块名。
  • <包名称>:希望对外开放的包名。
  • <目标模块>:允许访问该包的目标模块名,可以是模块的具体名称,也可以是特殊值 ALL-UNNAMED,表示允许类路径下的所有未命名模块(类路径上的旧式非模块化代码)访问。

示例

假设我们要启动一个程序,运行时需要向一个未命名模块(类路径下的代码)开放模块 java.base 的 java.lang.reflect 包:

代码语言:javascript
复制
java --add-opens java.base/java.lang.reflect=ALL-UNNAMED -jar app.jar  

含义:

  • java.base 是模块名称,这是 Java 自带的根模块。
  • java.lang.reflect 是要开放的包,该包位于 java.base 模块中。
  • ALL-UNNAMED 表示对所有未命名模块开放访问权限。

使用场景

  • 处理反射访问受限问题 某些老的框架或库在运行时使用了反射机制访问 Java 模块中的受限制方法或类,如果使用 JDK 9+,可能会报错类似 illegal access 或 IllegalAccessException。通过 --add-opens,可以临时解除这种限制。
  • 调试和开发 开发时,可能需要以反射方式访问模块化系统内的某些包,–add-opens 是解决这些问题的一种办法。
  • 向类路径中的非模块化代码(ALL-UNNAMED)开放访问 Java 模块化系统区分了模块(module)和非模块化的类路径代码(ALL-UNNAMED)。如果某些函数库还未模块化,可以用 --add-opens 打破包的边界。

注意事项

  1. 临时性 –add-opens 是一种临时、非优雅的解决方法。如果可能,应该尽量使用更加长期的手段,例如修改代码以适配 Java 模块化系统,或使用编译时模块描述符。
  2. 对合法性和安全性的影响 过多地使用 --add-opens 打破模块化系统的边界,可能会降低程序安全性和模块化带来的封装性,也是 Java 模块化设计的违背行为。
  3. 运行时而非编译时 –add-opens 的作用仅限运行时,可以用来解决运行期的反射错误,但并不会影响编译器的行为。如果在编译时遇到相关模块无法访问的问题,还需要用 --add-exports 或其他手段。

常见错误

    1. IllegalAccessException 或警告 如果未指定 --add-opens,并且代码反射访问了受限制的包,可能导致运行失败。

错误提示通常是:

代码语言:javascript
复制
java.lang.reflect.InaccessibleObjectException: Unable to make private method accessible:  
    1. 使用不匹配的模块名称 模块名称需要完全匹配,比如 java.base 是 Java 提供的模块的完整名称,不能写成部分名称或拼写错误。

和 --add-exports 的区别

–add-opens 和 --add-exports 都是解决 Java 模块化带来的访问限制的参数,但区别在于:

  • –add-opens 打开模块包的深度访问权限,不只是允许外部模块调用公共 API,还允许对非公共类型及成员(即通过反射)访问,通常配合反射使用。
  • –add-exports 仅开放模块包的公共 API(即 public 类型和成员),供目标模块调用,不涉及反射。

总结

–add-opens 用于在运行时允许外部模块通过反射访问指定模块的某个包,它更像是一种临时性补救措施,主要用于解决 Java 9+ 模块化带来的兼容性问题,

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 问题分析
  • 问题解决
  • 附录
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档