JEP 260:封装大多数内部 API
概括
默认情况下封装了 JDK 的大部分内部 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,它们似乎不会被 JDK 外部的代码使用,或者被外部代码使用只是为了方便,_即_支持的 API 中可用的功能或可以很容易地由库(例如,
sun.misc.BASE64Decoder
)提供的功能;和 -
提供关键功能的关键内部 API,在 JDK 本身之外实现这些功能即使不是不可能,也是很困难的(例如,
sun.misc.Unsafe
)。
关键的内部 API 是否封装在 JDK 9 中,取决于 JDK 8 中是否存在受支持的替换。受支持的替换是 Java SE 8 标准的一部分,_即_在java.*
或javax.*
包中,或者是 JDK 特定的 API并用 注释@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,并且如果模块声明了对模块的依赖关系,则模块中的代码也可以访问这些 API jdk.unsupported
。
在 JDK 9 中引入替代的关键内部 API 在 JDK 9 中已弃用,并将在未来版本中封装或删除。
jdk.unsupported
导出和打开sun.misc
和包的结果sun.reflect
是,这些包中的所有非关键内部 API 要么被移动到其他包,要么被删除(视情况而定)。不可升级的标准模块和 JDK 模块不应依赖于该jdk.unsupported
模块,而应使用适当的内部 API。
使用 JDK 9 中存在替换的关键内部 API 的库的维护者可能希望使用多版本 JAR 文件 (JEP 238),以便交付使用 JDK 9 之前版本上的旧 API 和 JDK 9 上的替换 API 的单个工件。稍后发布。
风险和假设
如果某些广泛使用的关键内部 API 未被识别为关键,并且该 API 被移动或删除,则依赖于它的应用程序将会失败。
如果某些广泛使用的关键内部 API 未被识别为关键但仍然存在,则依赖它的应用程序可能会导致在此版本中发出警告,并在未来版本中失败。
这两种情况的短期解决方法是最终用户通过上述命令行选项公开 API;从长远来看,在以后的版本中,API 可以移至模块jdk.unsupported
并导出以供外部使用。
sun.misc
之前存在于和包中的非关键内部 APIsun.reflect
已被移动或删除。依赖于它们的现有代码可能无法正常工作。
依赖关系
JEP 200(The Modular JDK)定义了JDK的模块化结构,JEP 261(Module System)实现了模块系统。