在 Java 9 中删除 sun.misc.Unsafe 将破坏 Spring、Hibernate
Posted
技术标签:
【中文标题】在 Java 9 中删除 sun.misc.Unsafe 将破坏 Spring、Hibernate【英文标题】:Removal of sun.misc.Unsafe in Java 9 will break Spring, Hibernate 【发布时间】:2015-10-03 17:19:00 【问题描述】:我读到here,如果 Oracle 在 Java 9 中删除 sun.misc.Unsafe
,Spring 和许多其他流行的库将会中断。但是,在 Spring 或 Hibernate 中没有对此类的静态引用。那么,这种说法是真的吗?
顺便说一句,Java 8 中有 64 个对 Unsafe
的引用,但如果 Oracle 删除了该类,它们将更新所有这些类,并且不会影响任何库(除非它们直接使用 Unsafe
)。
【问题讨论】:
Unsafe 不会从 JDK 中删除,只是被隐藏。所以JDK仍然可以在内部访问它。 Jigsaw 模块概念使这成为可能。 那么对于普通的 Java 开发人员来说,使用 maven 将 Spring-Hibernate 应用程序编译为 war 文件并将其放入 Tomcat / Jetty 意味着什么?我的应用程序会启动还是需要对容器进行调整才能使其工作? @Lluis Martinez 已经有合适的答案了吗?如果是,请您标记一个。 【参考方案1】:Mark Reinhold 在 2015 年 JVM 语言峰会期间发表了题为 The Secret History and Tragic Fate of sun.misc.Unsafe 的演讲。虽然这些谈话有很多免责声明,但您可以在10:23 看到建议的方法,在JEP260 中进行了描述。
大体思路是:
-
用更安全、受支持的 API 替换现有功能
弃用已被替换的先前存在的
Unsafe
API
在下一版本中删除不推荐使用的代码
以下是来自 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 中封装或删除。
【讨论】:
【参考方案2】:也许这些引用不在 Spring 或 Hibernate 的核心中,而是在其他地方。链接的文档说关于 Spring
Spring 框架(通过 Objenesis,带有后备)
我试图在我目前正在做的项目中搜索 Unsafe 的用法,所以仍然有相当多的库可能会损坏。
快速搜索结果:
番石榴 GWT 网络 泽西岛普通 Infinispan Jboss 模块【讨论】:
你说得对,Guava 有一些参考资料,但我读到它们提供了一个后备,所以它不是硬依赖。 github.com/google/guava/… Spring 中没有引用 github.com/spring/spring/… @LluisMartinez:您的链接指向“Spring RTS 游戏引擎”,“一种开源实时战略游戏引擎”。这与 OP 询问的 Spring 无关。 @Nicolai 哪个链接?顺便说一句,我是 OP :-) this comment中的链接。【参考方案3】:This 资源提供了对 JDK 9 的当前状态及其特性的正确理解。社区开始讨论有关 Unsafe 及其未来的 Java 未来。给定的文档是社区对JEP-260 做出反应的努力,该JEP-260 建议隐藏一些内部API,但保留一些关键API 可访问,包括女巫不安全。从文档本身中提取:
建议在 JDK 9 中保持可访问性的关键内部 API 是:
sun.misc.Cleaner
sun.misc.Signal,SignalHandler
sun.misc.Unsafe(本节中许多方法的功能 类现在可通过变量句柄 (JEP 193) 获得。)
sun.reflect.Reflection::getCallerClass(这个的功能 方法可以通过 JEP 259 以标准形式提供。)
sun.reflect.ReflectionFactory
因此得出结论,至少基于 given JEP,Unsafe 应该仍然存在。
【讨论】:
【参考方案4】:答案在链接的文档中。 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)创建类,而无需先调用构造函数。
【讨论】:
以上是关于在 Java 9 中删除 sun.misc.Unsafe 将破坏 Spring、Hibernate的主要内容,如果未能解决你的问题,请参考以下文章
201621123057 《Java程序设计》第9周学习总结