当前位置: 首页 > 知识库问答 >
问题:

Java`非法访问操作`方法将被弃用?[副本]

印季
2023-03-14

JDK9+JVM之后,如果您使用了一些非法访问,比如setaccessible(),JVM会发出非法访问操作警告。

我的问题

  1. setaccessible()将来会被阻止吗?
  2. 此功能的官方引用(如果不推荐的话)在哪里?

我在任何地方都找不到参考资料,提前谢谢。

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.hazelcast.internal.networking.nio.SelectorOptimizer (file:/var/folders/9w/wp9vfqmn2ql0mp3lgym0bxf40000gn/T/toy.war-spring-boot-libs-0024b388-730f-430b-b21b-1611bd2ad612/hazelcast-4.0.2.jar) to field sun.nio.ch.SelectorImpl.selectedKeys
WARNING: Please consider reporting this to the maintainers of com.hazelcast.internal.networking.nio.SelectorOptimizer
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

共有1个答案

解鸿运
2023-03-14

不,AccessibleObject#setAccessible(boolean)没有被否决,据我所知,也没有计划否决它。

您看到的警告与此方法有关,但不是直接的。Java9中引入的Java平台模块系统在编译时和运行时(即反射)都增加了更强的封装。运行时规则由#SetAccessible(boolean)记录:

C中的调用方可以使用此方法来启用对声明类D的成员的访问,如果保留以下任一项:

  • CD在同一个模块中。
  • 成员是公共的,d在包中是公共的,d包含d的模块至少导出到包含c的模块。
  • 成员受静态保护,D在包中是公共的,包含D的模块至少导出到包含C的模块,并且CD的子类。
  • D位于包含D的模块至少向包含C的模块打开的包中。未命名和打开模块中的所有包都对所有模块开放,因此当D位于未命名或打开模块中时,此方法总是成功。

当声明类位于调用方的不同模块中并且包含声明类的包未对调用方的模块打开时,此方法不能用于启用对私有成员、具有默认(包)访问权限的成员、受保护实例成员或受保护构造函数的访问。

与Java8相比,这是一个突破性的变化,当时反射可以自由地访问它想要的任何东西(假设没有SecurityManager)。一个突破性的变化是一个问题,因为Java以向后兼容性而自豪。为了给库和框架提供足够的时间进行迁移,他们放宽了这种针对特定场景的强封装(见下文)。

您看到的警告与--非法访问选项有关,该选项由Java工具规范记录:

当在运行时出现时,--illegal-access=接受一个关键字参数来指定操作模式:

注意:该选项将在未来的版本中删除。

>

  • permit:此模式打开运行时映像中每个模块中的每个包,以便在所有未命名的模块(例如类路径上的代码)中编码,如果该包存在于JDK 8中[着重号已添加]。这支持通过平台的各种反射API进行静态访问(例如,通过编译的字节码和深度反射访问)。对任何此类包的第一次反射访问操作将导致发出警告。但是,在第一次发生后不会发出警告。此单个警告描述如何启用进一步的警告。这种模式是当前JDK的默认模式,但在未来的版本中会发生变化[着重号已添加]。

    warn:此模式与permit模式相同,只是会对每个非法的反射访问操作发出警告消息。

    debug:此模式与warn模式相同,不同的是,每个非法的反射访问操作都会发出警告消息和堆栈跟踪。

    deny:此模式禁用所有非法访问操作,但其他命令行选项启用的操作除外,例如--add-opens。此模式将在未来的版本中成为默认[着重号已添加]。

    >

  • 如果组件的维护者已经发布了不再使用JDK内部API的固定版本,那么您可以考虑升级到该版本。

    如果组件仍然需要修复,那么您可以联系它的维护人员,要求他们用正确的导出API替换JDK-internal API的使用。

    如果必须继续使用需要非法访问的组件,则可以通过使用一个或多个--add-opens选项仅打开需要访问的内部包来消除警告消息。

    要验证您的应用程序是否为JDK的未来版本做好了准备,请使用--illegal-access=deny以及任何必要的--add-opens选项运行它。任何剩余的非法访问错误都很可能是由于从编译代码到JDK内部API的静态引用造成的。您可以通过使用--jdk-internals选项运行jdeps工具来识别这些代码。出于性能原因,当前JDK不会对非法静态访问操作发出警告。

    概括强调的部分:

    • 默认模式是permit
      • 这允许未命名模块(即类路径)中的代码访问运行时映像(即JDK)中模块内的成员,即使这些成员位于未导出/未打开的包中(只要这些包存在于JDK 8中)。
      • 任何在这一点上没有被正确迁移的代码都将停止工作。这就是为什么您会看到警告--他们希望您修复问题(如果是您的代码,您可以自己修复,如果是第三方代码,则通过提交bug报告修复)。

      这些变化将在什么版本中发生...我也不知道。但是,在默认模式变为deny后的一两个版本中,--intral-access选项可能会被删除。

      JEP396:强封装JDK内部默认情况下是用Java16交付的,并使默认模式deny--非法访问选项仍然存在。

      JEP403:强封装JDK内部是Java17当前的目标。这将使permitwarndebug模式无效,尝试使用它们将导致发出警告。但是,--非法访问选项目前仍将保留(但计划在未来的版本中删除)。

  •  类似资料:
    • 我正在为AmazonMQ编写一个简单的Java JMS QueueBrowser客户端,它通过< code>ssh运行带有< code>stomp协议的ActiveMQ(因此传输是< code>stomp ssl: 由于所使用的传输方式,我得到了一个< code > javax . JMS . JMS exception exec epion(我假设是< code>stomp ssl) Activ

    • 如果能帮助我重写一些使用反射的Java代码,以便在Java10上删除编译器中的警告,我将不胜感激: 这就是所讨论的Java方法: 这是GitHub上的问题代码:https://github.com/librepdf/openpdf/blob/master/openpdf/src/main/java/com/lowagie/text/pdf/mappedrandomaccessfile.java#l

    • 我正在使用Apache POI处理excel文件,从Java9开始,我得到了这条消息,根据这篇文章JDK9:发生了非法的反射访问操作。pySystemState我们应该等待开发人员修复这个问题,但是我应该在新的生产版本中保留它吗?我想跳过警告应该没问题。

    • 在尝试构建时,。我按照其他人的建议添加了,但仍然得到相同的错误。 有什么建议吗? pom.xml

    • 我试图使用Java9(JDK9)运行DMelt programs(http://jwork.org/DMelt/)程序,它给出了如下错误: 我该怎么修好它?我试图在脚本“dmelt.sh”的最后一行添加-illegal-access=permit(我在Linux中使用bash),但这并没有解决这个问题。我对此很沮丧。我经常使用这个程序,很长一段时间了。也许我永远不应该转到JDK9

    • 问题内容: 我正在尝试使用Java9(JDK9)运行DMelt程序(http://jwork.org/dmelt/)程序,它给了我以下错误: 我该如何解决?我试图将–illegal-access = permit添加到脚本“ dmelt.sh”的最后一行(我在Linux中使用bash),但这不能解决此问题。我对此感到非常沮丧。我经常使用此程序很长时间。也许我永远不应该转向JDK9 问题答案: 解决