我熟悉 Java 平台模块系统。
javadoc概述Module#addOpens
了一个我无法转化为现实世界的用例:
此方法可用于以下情况:消费者模块使用限定打开将包打开到API 模块,但对消费者模块中类成员的反射访问委托给另一个模块中的代码。API 模块中的代码可以使用此方法将消费者模块中的包打开到其他模块。
我承认我太笨了,无法从这个描述跳到现实世界。我可以看到这与以某种方式扩展深度反射访问有关,但我不确定那种方式是什么,特别是考虑到方法描述本身:
如果此模块 [“消费者模块”?可能吗?] 至少已向调用者模块 [“ API 模块”?可能吗?] 打开了一个包,则更新此模块以向给定模块 [“其他模块”?可能吗?] 打开该包。
我有一种模糊的、几乎肯定是错误的感觉,这与我的模块(“消费者模块”?)打开一个包到 Servlet(“API 模块”?)之类的东西有关,但在运行时不知道 Servlet 的实现实际上是(比如说)Tomcat,所以,如果我的代码希望,它(我想?)可以调用这个方法,从而以某种方式允许 Tomcat(“其他”模块?)做反射的事情,而不知道它实际上是 Tomcat(而不是 Jetty)在做那些反射的事情,也不必有opens com.foo.bar to Tomcat
额外module-info
的opens com.foo.bar to Servlet
。
(我也不确定“委托”应该发生在哪里;在这种情况下,Servlet 不能将任何事情“委托”给 Tomcat。)
但考虑到Lookup
调用站点敏感度限制,我不确定这应该如何工作,或者在这种情况下我应该在代码中的何时何地进行此类调用,或者为什么如果我已经添加了opens
语句,我现在还必须执行一些编程操作。我理解完整性的激励目标,并且必须授予反射访问的权限,并且这应该以某种方式使事情变得更容易,但我无法具体实现这一点。
简而言之:这个功能实际上有具体的用例吗?如果有,它是什么?它是如何工作的?
Jakarta xml bind 代码在
jakarta.xml.bind.ModuleUtil.delegateAddOpensToImplModule
源代码在这里
在 JDK Javadoc 代码中
TagletManager
也jdk.javadoc.internal.doclets.formats.html.taglet
使用了这一点。大多:
修补
如果您想通过修补来“就地”编辑模块(您调用其私有方法或在运行时对其进行修改,而不是从源代码分叉它,编辑该源代码,并发布修改后的分叉),您可以使用来访问您正在修补/扩展的内容的内部结构
--add-opens
。遗产
这是一个带有负面含义的术语,但这里不是这个意思:很多事情只有通过反射才有可能,而 OpenJDK 已经通过使反射不再可能而彻底破坏了一些东西。有时,有足够的替代品可用。但有时,没有。
--add-opens
可以恢复功能,而不需要库作者变出一只兔子。--add-opens
通常,您会在命令行上执行这些操作,但是当现有系统在启动时设置了适当的开关,并且稍后对其应用程序进行了一些重构,并且最终托管需要“打开”权限的代码的实际模块是某个子模块时,您可以使用addOpens
方法将Module
模块的额外打开权限“扩展”到您的子模块。这样,例如您的启动脚本或您的 cronjobs 或诸如此类的东西(启动应用程序的实际命令写入的地方java --add-opens
)就不需要修改了。