Java 9中删除sun.misc.Unsafe将破坏Spring和Hibernate。

15
我在这里读到,如果Oracle在Java 9中删除sun.misc.Unsafe,Spring和许多其他流行的库将会崩溃。然而,在Spring或Hibernate中没有对该类的静态引用。那么,这个说法是真的吗?
顺便说一下,在Java 8中有64个对Unsafe的引用,但是如果Oracle删除了该类,他们将更新所有引用,没有任何库会受到影响(除非他们直接使用Unsafe)。

6
Unsafe不会从JDK中移除,只是被隐藏了起来。因此,JDK仍可以在内部访问它。这得益于Jigsaw模块化的概念。 - Uwe Schindler
那么对于普通的Java开发人员来说,使用maven将Spring-Hibernate应用程序编译为war文件并将其放入Tomcat / Jetty中,这意味着什么?我的应用程序会启动还是需要调整容器才能使其正常工作? - Jan Vladimir Mostert
@Lluis Martinez 这个问题已经有合适的答案了吗?如果有,请标记一个答案。 - Naman
4个回答

10

Mark Reinhold在JVM语言峰会2015上发表了一篇名为The Secret History and Tragic Fate of sun.misc.Unsafe的演讲。尽管这些演讲有很多免责声明,但您可以在10:23看到所提出的方法,这在JEP260中有描述。

总体思路是:

  1. 使用更安全、更受支持的API替换现有功能
  2. 将已被替换的以前存在的Unsafe API标记为过时
  3. 在下一个版本中删除废弃的代码

以下是来自JEP260的相关文本(摘自2015年10月20日):

在JDK 9中,我们提出以下措施:
  • 默认情况下封装所有非关键的内部API:定义它们的模块不会将其包导出供外部使用。(可以通过命令行标志在编译时和运行时访问这些API,除非这些API由于其他原因被修改或删除,否则只能作为最后的手段。)

  • 以相同的方式和同样的最后手段封装具有支持替代品的JDK 8关键内部API。(支持替代品是指Java SE 8标准的一部分(即在java.*或javax.*包中),或者是JDK特定的,并用@jdk.Exported注释(通常在com.sun.*或jdk.*包中)。)

  • 不封装JDK 8中不存在支持替代品的关键内部API,并弃用那些在JDK 9中存在支持替代品的API,目的是在JDK 10中对它们进行封装或甚至删除。

...

JDK 9中引入替代品的关键内部API将在JDK 9中被弃用,并在JDK 10中被封装或移除。


6

这个资源提供了对JDK 9及其功能的透彻理解。社区开始就Unsafe及其在Java未来中的地位展开讨论。给定的文档是社区应对JEP-260的努力,该提案建议隐藏一些内部API,但保留一些关键API,其中包括Unsafe。如从文档本身中提取的:

建议在JDK 9中仍然可以访问的关键内部API是:

sun.misc.Cleaner

sun.misc.{Signal,SignalHandler}

sun.misc.Unsafe(现在此类中许多方法的功能可通过变量句柄(JEP 193)获得。)

sun.reflect.Reflection::getCallerClass(该方法的功能可能会以标准形式通过JEP 259提供。)

sun.reflect.ReflectionFactory

因此,总的来说,至少根据给定的 JEP,Unsafe 应该保留。

5
也许这些引用不在Spring或Hibernate的核心代码中,而是在其他地方。所链接的文档针对Spring表示:

Spring Framework (通过Objenesis,并提供备选方案)

我尝试搜索了一下我目前正在工作的项目中Unsafe的使用情况,还有一些库可能会出现问题。
快速搜索的结果如下:
  • Guava
  • GWT
  • Netty
  • Jersey-Common
  • Infinispan
  • Jboss-Modules

1
你说得对,Guava有一些引用,但我读到它们提供了一个回退,所以它不是一个硬依赖。https://github.com/google/guava/search?utf8=%E2%9C%93&q=sun.misc.unsafe - Lluis Martinez
1
没有Spring中的参考文献:https://github.com/spring/spring/search?utf8=%E2%9C%93&q=sun.misc.unsafe - Lluis Martinez
1
@LluisMartinez:你的链接指向“Spring RTS游戏引擎”,这是一个开源实时策略游戏引擎。这与OP所问的Spring没有任何关系。 - Nicolai Parlog
@Nicolai 哪个链接?顺便说一下,我是 OP :-) - Lluis Martinez
此评论中的链接。 - Nicolai Parlog

3
答案在链接的文档中。Spring没有直接依赖于Unsafe,但是Spring依赖于Objenesis,而Objenesis又依赖于Unsafe
Objenesis对Unsafe的依赖: https://github.com/easymock/objenesis/blob/master/main/src/main/java/org/objenesis/instantiator/sun/UnsafeFactoryInstantiator.java
Spring对Objenesis的依赖本身有点奇怪。Spring的构建脚本获取Objenesis二进制文件,并使用JarJar工具进行字节码级别的更改。您可以在以下构建脚本中看到它的操作:https://github.com/spring-projects/spring-framework/blob/master/build.gradle(编写时,请参见326-343行和347行)。
这基本上意味着Spring的"spring-core"二进制文件最终包含一堆位于org.springframework.objenesis.*包结构下的类,但这些类最初存储在Objenesis GitHub中的源代码中,由Objenesis团队发布为二进制文件,然后在Spring构建期间获取、重新打包为org.springframework.*包,并作为Spring的一部分重新发布。这就是为什么您找不到它们的原因。
Spring使用Unsafe(通过Objenesis)来创建在未调用构造函数的情况下的类。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接