原文:JEP 11: Incubator Modules

摘要

孵化器模块是一种将非最终版 API、工具交给开发者的方式,与此同时,这些 API、工具成为最终版或者被从未来版本中移除。

目标

支持 JDK Release 项目分发一些半成品的 API、工具,以从开发者或用户反馈中获益。这将减少在 Java SE Platform 和 JDK 中犯成本高昂的错误的机会。

非目标

  • 不是要定义一个通用机制,来分发二进制的非 JDK 模块。
  • 不是要为模块、API、工具定义全生命周期。
  • 不是要求所有为 JDK 开发的特性都要(在生命周期的某个点)这样孵化(尽管这是我们所希望的)。
  • 不是要定义一种机制,来孵化语言或 VM 特性,但是任何未来的机制应该使用孵化器模块来孵化相关 API。

动机

许多 Java SE 平台 API、支持的 JDK API、广泛使用的 JDK 工具应该在被 JCP 标准化或者被视为稳定之前经过一个 JDK Release Project 的孵化阶段,并从中获益。通过 JDK Release 项目孵化,以及在下游的二进制包中——如 jdk.java.net 里的这些,将使得 OpenJDK 核心社区之外的团体能更容易地使用新特性。增长的经验和通过常用渠道,如博客、邮件列表、推广程序、会议,收集到的反馈能作用于未来发布项目中是保留或移除该特性。

描述

一个孵化中的特性是一个 API 或工具,具有相当规模,正在开发中,将最终包含到 Java SE Platform 或 JDK 中。因为 API 或工具尚未经过充分验证,所以会通过几个小的特性发布版本来收集额外的经验和反馈,以为未来标准化和定稿做准备。

孵化器模块是 JDK Release Project 中提供孵化特性的模块:要么提供了孵化中的 API,要么提供了孵化中的工具,要么同时提供了两者。

孵化 API 被定义在 jdk.incubator. 这个导出包前缀下。一个孵化 API 只会包含在一个孵化模块中。

孵化工具也可以在命令行调用的工具名称中使用 jdk.incubator 前缀,但不是必须。

当一个孵化 API 被标准化或被晋升为 JDK 中的稳定内容,所在包将被重命名并从非孵化模块中导出路径。早期采用者应该仅需要修改 import 语句,在 API 本质上变更了很多的情况下也可能需要重构使用方式。同样的,当孵化工具稳定存在后,早期采用者也可能需要修改调用脚本,以适配工具的功能调整和命令行接口调整。

如果孵化 API 经过几个 JDK 特性版本后未被标准化或晋升,则不再孵化,相关的包和孵化模块将被移除。同样的,如果孵化工具没有晋升,对应的孵化器模块也会被移除。

过程和演化

孵化一个特性(API 或 工具)会用到 JEP 流程,包含下列指导原则:

  1. JEP 需要清晰定义计划孵化的特性,完成的标准是形成一个导出 API 或包含工具的孵化器模块。
  2. 一个孵化特性,如有任何的演进变更,都应该提交一个新的 JEP 来记录这些变更。允许(而非要求)新 JEP 将晋升后 API 或工具放到单独的模块中;API 或工具也可以被整合进现有的标准模块或非孵化器 JDK 模块中。
  3. 如果一个孵化特性被移除了,这种情况不需要提交新的 JEP。包含该孵化特性的孵化器模块将被静默移除。推荐在原始 JEP 中记录一下特性的最终命运。

一个孵化器模块应包含一个孵化特性。(如果一个孵化工具关联了一个 API,这个 API 就被视为该工具的一部分,将被包含该工具的孵化器模块导出)一个孵化器模块对应一个孵化特性有助于防止混合孵化器模块的出现,这种模块就像一个大垃圾堆,过去我们已经在 sun.* 命名空间下的一些部分看到了这种情况。孵化特性及其未来(或没有)都有明确的负责人。

一个孵化特性不能一直待在引入时的 JDK Release Project 中,也不能包含在继承自 Release Project 的下游的每一个二进制发版中。举个例子,在 JDK Release Project 的不同的更新迭代中,孵化特性可能进化,也可能被移除。除了这个关于何时可以演进的明确声明外,本提案不提供更多的指导。这些决定最好是留给特性的所有者来决定。

孵化模块和它的 API/工具,不会长期存在 JDK 中,某种意义上他们诞生之初就是要被废弃的(博主:任一孵化模块一定会被废弃)。但是,把孵化和废弃理解为两个完全不同的概念会更清爽,所以 @Deprecated 注解和 @deprecated JavaDoc 标签不应该用在孵化模块中或他们的 API 上。

和其他模块的关系

孵化器模块必须且只能导出孵化 API,即存在 jdk.incubator 命名空间下的包。因此:

  • 孵化器模块不得导出在 java. 或 javax. 命名空间下的 API,这 2 个命名空间由 JCP 控制。这就将孵化器模块和标准模块(如 java.base)区分开。
  • 孵化器模块不得导出承诺会提供呢支持的 API。这就将孵化器模块和会导出这类 API 的 JDK 模块(如 jdk.compiler)区分开。
  • 孵化器模块不得导出核心内部 API。孵化器模块和 jdk.unsupported 模块没有任何关系。

标准模块和非孵化器 JDK 模块不得声明传递依赖于孵化器模块,也不得在自己的导出 API 中暴露来自孵化器模块定义的类型。在特殊情况下,可以允许标准模块或者非孵化器模块声明依赖孵化器模块(而不是要求传递依赖)。

孵化器模块可以声明依赖或传递依赖于孵化器模块。

孵化器模块是标准 JDK 构建的 JDK 运行时镜像的一部分。但是,默认情况下,孵化器模块不在应用的 class path 下被解析。甚至,默认情况下,孵化器模块不参与 class path 或 module path 下绑定到应用的服务。

class path 下的应用必须使用 –add-modules 命令选项来解析一个孵化器模块。模块开发时可以声明依赖或者传递依赖于孵化器模块。(一些孵化器模块,比如提供命令行工具的,不会导出任何包,代之以实现的服务,这样工具就能在编码时被引用。通常不鼓励一个模块不导出任何包,但这里例子里是必要的,以便解析孵化器模块,并将服务提供者绑定到服务。)

在 JDK 构建过程中,必须使用 jmod 工具的 –do-not-resolve-by-default 选项将孵化器模块打包进 jmod 文件中,这样孵化器模块就不会作为未命名模块出现在根模块的默认集中。这使得需要明确选择孵化器模块。同时,必须传递 –warn-if-resolved=incubating 选项给 jmod 工具,以便在编译、链接、运行时解析了孵化器模块时给予警告。在编译时可以抑制这个警告,但链接和运行时不行。

孵化器模块没有默认的安全权限。

孵化器模块可以是特定于操作系统的。

整合点

许多新 API 希望融合进 Java SE 平台的 java.* 和 javax.* API 里,但是在孵化期间,API 应该待在 jdk.inicubator. 命名空间里以和 SE API 分开。 例如,Streams API:对设想中的 jdk.incubator.stream.Streams 类来说,提供一个静态工厂方法,如 fromList,fromSet 等,是必要的,以整合进当前的 Collections API 里。虽然这只是一个折衷方案,和当前 SE API 的整合点通常只涉及新 API 很小的一部分。

在一些情况下,孵化特性也可能紧密整合进了 Java 运行时和 JVM 里。在这样的案例中,底层操作可以通过 JDK 中相应模块的限定导出开放给需要该特性的孵化器模块。有至少一个 JDK 模块限定导出的孵化器模块就是紧耦合的,即它的哈希被记录到了导出模块中,导致孵化器模块无法升级。一个没有限定导出模块的孵化器模块不需要紧耦合,因此是可升级的。如果要求在 JVM 里提供底层孵化支持,那就有必要提供一个命令行参数,如 -XX:+UnlockExperimentalVMOptions,或其他安排以在有孵化器模块存在时自动进行支持。

文档

和 JDK 中的其他 API 一样,一个孵化中的 API 也有自己的 JavaDoc。一个额外的目录结构,jdk/incubator/ 将被添加用来存放孵化特性的文档,基于每个孵化器模块一个孵化特性的模式。对孵化特性的状态,所有孵化中 API 的 JavaDoc 都有显式、明显、一致地警告信息,同时提醒这个特性最终是要被移除的。

其他选项

许多新特性和 Java 运行时系统及 JVM 紧耦合。独立于 JDK 发布这些新特性是困难的,即使是可能的,所以它们需要和特定发版的特定构建紧密结合。和 JDK 一起发布保障了所有必要的部分都是紧密结合在一起的。

JDK Release Project 或另一个项目的二进制预览(EA)版本将持续提供,以便开发者能进行试用并在 GA 版前提供反馈。但 EA 版的下载量比 GA 版少很多,因为绝大部分开发者都想要 GA 版的高稳定性和高质量。如此一来,EA 版本的用户只有有限的注意力,给出的反馈也有限,但孵化中的特性的目标是更广泛的开发者,因此需要寻求广泛的关注和详尽的反馈。这使得 GA 版成为承载新孵化特性的更好选择。

测试

包含孵化特性的代码需要和 JDK 里的其他部分一样被测试。输出孵化特性的 JEP 里应突出特定特性的测试需求。

风险和假设

孵化特性最显著的风险是有开发的代码或脚本依赖了它,然后在后面的版本中被破坏了,因为孵化器模块已经被移除。通过保证孵化特性是主动选择的,可以缓解风险,即通过默认不解析孵化器模块,和当解析孵化器模块时在所有阶段都发出警告。

分类: 扯淡

0 条评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注