Answers:
除了了解模块及其各自程序包之间的访问。我相信它的症结在于模块系统#Relaxed-strong-encapsulation,我只是挑选它的相关部分来尝试回答这个问题。
什么定义了非法的反射访问,什么情况触发了警告?
为了帮助迁移到Java-9,可以放松对模块的强封装。
一个实现可以提供静态访问,即通过编译的字节码。
可以提供一种方法,用其一个或多个模块的一个或多个软件包打开其运行时系统,以在所有未命名模块中进行编码,即在类路径上进行编码。如果以这种方式调用运行时系统,并且这样做,则反射API的某些调用将成功,否则它们将失败。
在这种情况下,实际上您实际上是进行了“非法”的反射访问,因为在纯模块化的世界中,您无意进行此类访问。
在所有情况下,它们如何相互关联以及触发该警告的原因是什么?
封装的放松是在运行时由新的启动器选项控制的,--illegal-access
在Java9中默认情况下等于permit
。该permit
模式确保
对任何此类包装的第一次反射式访问操作都会导致发出警告,但在此之后不再发出警告。此单个警告描述了如何启用进一步的警告。此警告不能被抑制。
可以使用值debug
(每个此类访问的消息和堆栈跟踪),warn
(每个此类访问的消息)和deny
(禁用此类操作)值来配置模式。
调试和修复应用程序的几件事是:
--illegal-access=deny
来了解并避免在没有模块声明(包括此类指令()或显式使用VM arg )的情况下将软件包从一个模块打开到另一个模块。opens
--add-opens
jdeps
带有--jdk-internals
选项的工具,可以识别从已编译代码到JDK内部API的静态引用。检测到非法反射访问操作时发出的警告消息具有以下形式:
WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM
哪里:
$PERPETRATOR
是类型的标准名称,其中包含调用了相关反射操作的代码以及代码源(即JAR文件路径)(如果有),并且
$VICTIM
是描述正在访问的成员的字符串,包括封闭类型的全限定名称
有关示例警告的问题:= JDK9:发生了非法的反射访问操作。org.python.core.PySystemState
最后一个重要说明,在尝试确保您不会遇到此类警告并日后安全时,您需要做的就是确保您的模块没有进行那些非法的反射访问。:)
默认情况下,除非是公共类型并且您导出其包,否则其他模块将无法访问模块中的类型。您只公开要公开的软件包。对于Java 9,这也适用于反射。
如https://stackoverflow.com/a/50251958/134894所指出AccessibleObject#setAccessible
,JDK8和JDK9 之间的区别是有启发性的。具体来说,添加了JDK9
如果满足以下任何条件,则类C中的调用者可以使用此方法来允许访问声明类D的成员:
- C和D在同一模块中。
- 在包含D的模块至少导出到包含C的模块的包中,成员是public且D是public。
- 成员受到静态保护,D在包含D的模块至少导出到包含C的模块的包中是公共的,并且C是D的子类。
- D在包含D的模块至少打开包含C的模块的包中。未命名和打开的模块中的所有包都向所有模块开放,因此,当D在未命名或打开的模块中时,此方法始终成功。
强调了模块及其导出的重要性(在Java 9中)
–illegal-access=permit
... 启动JVM
fun
只需查看setAccessible()
用于访问private
字段和方法的方法即可:
现在,要使此方法起作用,还需要更多条件。不会破坏几乎所有旧版软件的唯一原因是,从普通JAR自动生成的模块是非常宽松的(为所有人打开和导出所有内容)。
如果要使用add-open选项,请使用以下命令查找哪个模块提供了哪个软件包->
java --list-modules | tr @ " " | awk '{ print $1 }' | xargs -n1 java -d
模块的名称将显示@,而没有名称的软件包的名称
注意:已通过JDK 11测试
重要提示:显然比不对软件包的提供者进行非法访问更好