Skip to content

JEP 260: Encapsulate Most Internal APIs | 封装大部分内部 API

摘要

默认情况下封装大部分 JDK 的内部 API,使得在编译时无法访问这些 API,并准备将来的版本中也将无法在运行时访问这些 API。确保关键、广泛使用的内部 API 不会被封装,以便在所有或大多数功能都有支持替代品之前仍然可以访问。

非目标

此 JEP 不定义任何内部 API 的替换;这项工作将由单独的 JEP 和(在适当的情况下)JSR 完成。

该 JEP 不承诺保留任何内部 API 在发布之间的兼容性;它们继续保持不稳定,并且随时可能发生变化而没有通知。

动机

一些流行的库使用了非标准、不稳定和不受支持的 API,这些 API 是 JDK 的内部实现细节从未旨在供外部使用。在模块化 JDK(JEP 200)中,通过利用模块系统(JEP 261),限制对这些 API 的访问可以提高平台的完整性和安全性,因为这些内部 API 中的许多定义了特权的、安全敏感的操作。从长远来看,这种变化将减少 JDK 本身维护者和库和应用程序的维护者承担的成本,这些库和应用程序知道或不知道地使用这些内部 API。

描述

基于对各种大型代码集合(包括 Maven Central)进行的分析,以及自 JDK 8 及其依赖项分析工具jdeps)发布以来收到的反馈,我们将 JDK 的内部 API 分为两个广泛的类别:

  • 非关键内部 API:这些 API 似乎没有被外部代码使用,或仅被外部代码用于方便起见,即所需的功能可以通过支持的 API 或库(例如sun.misc.BASE64Decoder)轻松提供。

  • 关键内部 API:这些 API 提供了关键功能,在 JDK 本身之外实现这些功能会很困难,如果不是不可能的话(例如sun.misc.Unsafe)。

关键内部 API 根据 JDK 8 中是否存在支持替代品,在 JDK 9 中封装或否定。支持的替换物是指在 Java SE 8 标准中的一个(即在 java.*javax.* 包中),或者是 JDK 特定的,并且用 @jdk.Exported 进行注释,通常在 com.sun.*jdk.* 包中。具体来说:

  • 在 JDK 8 中存在支持替代品的关键内部 API 封装在 JDK 9 中。

  • 在 JDK 8 中不存在支持替代品的关键内部 API 不封装在 JDK 9 中。下面提供了详细的列表。

  • 在 JDK 9 中存在支持替代品的关键内部 API 已被弃用,并将在未来的版本中封装或删除。

所有非关键内部 API 都在 JDK 9 中封装。

在 JDK 9 中封装的内部 API 在编译时无法访问。可以通过--add-exports命令行选项使它们在编译时可访问。在运行时,如果它们在 JDK 8 中,则仍然可以访问,但在将来的版本中,它们将变得无法访问,在这种情况下,可以使用--add-exports--add-opens选项使它们在运行时也可以访问。 --illegal-access选项控制这些 API 的运行时可访问性,并且可以用于模拟内部 API 的未来运行时不可访问性。

未在 JDK 9 中封装的关键内部 API

以下是未在 JDK 9 中封装的关键内部 API,因为在 JDK 8 中不存在支持的替代品。

  • sun.misc.{Signal,SignalHandler}

  • sun.misc.Unsafe(这个类中许多方法的功能可以通过变量句柄(JEP 193)实现。)

  • sun.reflect.Reflection::getCallerClass(int)(此方法的功能可在由 JEP 259 定义的堆栈行走 API 中获得。)

  • sun.reflect.ReflectionFactory

  • com.sun.nio.file.{ExtendedCopyOption,ExtendedOpenOption, ExtendedWatchEventModifier,SensitivityWatchEventModifier}

这些 API 在 JDK 特定的 jdk.unsupported 模块中定义并导出。此模块存在于全 JRE 和 JDK 映像中。因此,这些 API 默认情况下对类路径上的代码可访问,并且对模块中的代码可访问,如果这些模块声明依赖于 jdk.unsupported 模块。

JDK 9 中引入替代物的关键内部 API 在 JDK 9 中已弃用,并将在未来的版本中封装或删除。

导出和打开sun.miscsun.reflect包的 jdk.unsupported 模块的结果是,这些包中的所有非关键内部 API 都已移动到其他包中或已被删除,视情况而定。不能升级的标准 JDK 模块不应该依赖于 jdk.unsupported 模块,而应使用适当的内部 API。

使用在 JDK 9 中存在替换品的关键内部 API 的库的维护者可能希望使用多版本 JAR 文件(JEP 238),以便在 JDK 9 之前的版本上使用旧的 API,并在后续版本上使用替换的 API 发布单个构件。

风险和假设

如果未将某些广泛使用的关键内部 API 标识为关键,并且将该 API 移动或删除,则依赖它的应用程序将失败。

如果未将某些广泛使用的关键内部 API 标识为关键但仍然存在,则依赖它的应用程序可能会在此版本中发出警告,并且将在将来的版本中失败。

这两种情况的短期解决方法是让最终用户通过上述命令行选项公开 API;在较长时间内,在以后的版本中,可以将 API 移动到 jdk.unsupported 模块并导出以供外部使用。

先决条件

JEP 200(模块化 JDK)定义了 JDK 的模块化结构,JEP 261(模块系统)实现了模块化系统。