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.misc
和sun.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(模块系统)实现了模块化系统。