什么是非法的反射访问

b0zn9rqh  于 2021-07-11  发布在  Java
关注(0)|答案(4)|浏览(361)

关于Java9中的非法反射访问有很多问题。
现在我找不到的是,因为google所说的都是人们试图绕过错误信息,这实际上是一种非法的反射访问。
所以我的问题很简单:
什么定义了非法的反射访问以及什么情况触发了警告?
我已经收集到,它与Java9中引入的封装原则有关,但是它是如何结合在一起的,在什么样的场景中触发警告,我找不到解释。

xbp102n0

xbp102n01#

除了了解模块之间的访问及其各自的包。我相信它的关键在于模块系统#宽松的强封装性,我只想挑选它的相关部分来尝试回答这个问题。
什么定义了非法的反射访问以及什么情况触发了警告?
为了帮助迁移到java-9,可以放宽模块的强封装。
实现可以提供静态访问,即通过编译的字节码。
可以提供一种方法来调用其运行时系统,使其一个或多个模块的一个或多个包对所有未命名模块中的代码开放,即在类路径上编码。如果以这种方式调用运行时系统,并且如果这样做,反射api的一些调用将成功,否则它们将失败。
在这种情况下,您实际上已经结束了一个反射访问,这是“非法的”,因为在一个纯粹的模块化世界中,您不应该做这样的访问。
它们是如何联系在一起的?在什么情况下触发警告的是什么?
这种封装的放松在运行时由一个新的启动程序选项控制 --illegal-access 在java9中,默认情况下等于 permit . 这个 permit 模式确保
对任何此类包的第一次反射访问操作都会发出警告,但在该点之后不会发出警告。此单个警告描述如何启用进一步的警告。无法抑制此警告。
模式可通过值进行配置 debug (消息以及每次访问的stacktrace), warn (每次访问的消息),以及 deny (禁用此类操作)。
在应用程序上调试和修复的内容很少:-
和我一起跑 --illegal-access=deny 了解并避免在没有包含此类指令的模块声明的情况下打开从一个模块到另一个模块的包( opens )或明确使用 --add-opens vm参数。
从编译代码到jdk内部api的静态引用可以使用 jdeps 带有 --jdk-internals 选项
检测到非法反射访问操作时发出的警告消息具有以下形式:

WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

哪里: $PERPETRATOR 类型的完全限定名,其中包含调用所讨论的反射操作的代码以及代码源(即jar文件路径)(如果可用),以及 $VICTIM 描述要访问的成员的字符串,包括封闭类型的完全限定名
有关此类示例警告的问题:=jdk9:发生了非法的反射访问操作。org.python.core.pysystemstate
最后一点也是一个重要的注意事项,在试图确保您不会面临此类警告并且是未来安全的同时,您所需要做的就是确保您的模块不会进行这些非法的反射访问。:)

8hhllhi2

8hhllhi22#

我发现了一篇关于java9模块系统的oracle文章
默认情况下,模块中的类型不能被其他模块访问,除非它是公共类型并且您导出了它的包。只公开要公开的包。对于Java9,这也适用于反射。
正如在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位于未命名模块或打开模块中时,此方法总是成功的。
它强调了模块及其导出的重要性(在Java9中)

crcmnpdw

crcmnpdw3#

你看看 setAccessible() 用于访问的方法 private 字段和方法:
https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/accessibleobject.html#setaccessible-布尔值-
https://docs.oracle.com/javase/9/docs/api/java/lang/reflect/accessibleobject.html#setaccessible-布尔值-
现在这种方法需要更多的条件才能发挥作用。它没有破坏几乎所有旧软件的唯一原因是,从普通jar自动生成的模块非常允许(为每个人打开并导出所有内容)。

puruo6ea

puruo6ea4#

如果您想使用addopen选项,这里有一个命令来查找哪个模块提供了哪个包-> java --list-modules | tr @ " " | awk '{ print $1 }' | xargs -n1 java -d 模块的名称将与@一起显示,而没有它的包的名称将与@一起显示
注:用jdk 11测试
重要提示:显然比提供程序包不做非法访问要好

相关问题