JEP 320: Remove the Java EE and CORBA Modules | 移除 Java EE 和 CORBA 模块
摘要
从 Java SE 平台和 JDK 中移除 Java EE 和 CORBA 模块。这些模块在 Java SE 9 中已被弃用,并明确表示将在未来的版本中移除它们。
动机
Java SE 6 为了方便 Java 开发者,包含了一个完整的 Web 服务栈。这个栈由四种技术组成,这些技术 最初 是为 Java EE 平台 开发 的:JAX-WS(Java API for XML-Based Web Services)、JAXB(Java Architecture for XML Binding)、JAF(JavaBeans Activation Framework)和 Common Annotations。在包含这些技术时,Java SE 中的版本与 Java EE 中的版本完全相同,除了 Java SE 删除了 Common Annotations 中与 Java EE 安全模型相关的包。然而,随着时间的推移,Java EE 中的版本不断演进,这给 Java SE 中的版本带来了困难:
这些技术增加了与 Java SE 无关的功能。例如,Common Annotations 在 Java EE 6 中添加了一个与 Java EE 容器中数据源相关的包。这使得必须定期对这些 Java EE 版本进行快照和子集化,这对于 JDK 工程师来说是耗时的,对于开发者来说是令人困惑的。
这些技术由上游项目在 java.net 上维护,后来又在 GitHub 上维护。这使得维护变得困难,因为需要将 OpenJDK 存储库中的 Java SE 版本与上游存储库中的 Java EE 版本同步。
开发者可以从上游项目获得这些技术的独立版本,这导致他们可能会使用与 JDK 捆绑的版本不同的版本。这可能导致兼容性问题,因为 JDK 中的版本可能落后于上游项目中的版本。
开发者可以从上游项目中获取这些技术的独立版本,并通过 Endorsed Standards Override Mechanism 进行部署。这个长期存在的机制允许独立版本安全地覆盖 Java SE 版本。然而,在实践中,这一机制并未得到广泛应用,开发者反而使用临时机制来部署独立版本,比如将它们置于 JDK 的引导类路径之前,或者简单地将它们放在类路径上,并希望由此产生的分割包不会引发问题。
由于 Java EE 技术的独立版本很容易从第三方网站(如 Maven Central)获取,因此 Java SE 平台或 JDK 没有必要包含它们。
另一个 Java SE 为方便开发者而包含技术的案例可以追溯到 1998 年。在 Ken Cavanaugh 的杰出领导下,Java SE 通过提供 OMG CORBA API、ORB 实现、CosNaming 实现、idlj
编译器以及在 rmic
编译器中对 IDL 和 IIOP 的支持,来 接纳CORBA。然而,随着时间的推移,对 CORBA 的支持变得问题重重:
由于 CORBA 是一个“Endorsed Standard”,在 Java 社区进程之外发展,因此与 Web 服务类似的评论也适用于 JDK 中 CORBA 的维护以及安全覆盖 JDK 中 CORBA 实现的能力。将 JDK 中的 ORB 与 Java EE 应用服务器中的 ORB 同步,几乎没有现实的前景。
在 Java 中使用 CORBA 开发现代应用程序的兴趣并不显著。此外,Java EE 8 将 CORBA、RMI-IIOP 和 JavaIDL 列为“拟议的可选”,这表明这些技术所需的支持可能会在未来的版本中取消。
由于维护 CORBA 支持的成本超出了其带来的好处,因此 Java SE 平台或 JDK 没有理由包含它。
最后,自 Java SE 1.3 以来,Java SE 包含了一个 JTA(Java 事务 API)的子集,自 Java SE 5.0 以来,还包含了一个 J2EE 扩展事务活动服务(J2EE Activity Service)的子集。
JTA 由两个包组成,这两个包各自扮演着不同的角色并值得进行不同的处理:
javax.transaction.xa
包支持 JDBC 中的 XA 事务。这个“XA 包”与 JDBC 一同位于 Java SE 9 的java.sql
模块中。由于java.sql
模块不可升级,因此无法用 JTA 的独立版本覆盖 Java SE 版本的 XA 包,但这对于应用程序来说通常是可接受的,因为 XA 包多年来一直保持稳定,且 Java SE 版本与 Java EE 版本相同。为便于维护,Java SE 中的 XA 包将来可能会移动到另一个不可升级的模块中,但作为一种架构上的考虑,它将长期与 JDBC 一起留在 Java SE 中,并且与本 JEP 无关。javax.transaction
包定义了一个通用的事务管理 API。这个包的 Java EE 版本一直超出了 Java SE 的范围,并且以与 Java SE 无关的方式发展。例如,JTA 在 Java EE 7 中添加了一些与 CDI 相关的类型。Java SE 定义的javax.transaction
子集支持与 CORBA 事务服务的互操作性。这个“CORBA 互操作包”在 Java SE 9 中存在于其自己的java.transaction
模块中。然而,对于使用 CORBA 事务服务的应用程序来说,Java SE 版本通常是不可接受的,因此它们通常会使用 Java EE 版本来覆盖它。
J2EE 活动服务定义了一个通用的中间件 API。自 2006 年以来,它一直没有更新,并且不是 Java EE 平台的一部分。它之所以与这个 JEP 有关,只是因为 Java SE 包含其 javax.activity
包的一个子集,用于与 CORBA 事务服务进行互操作。这个“活动包”存在于 Java SE 9 的 java.corba
模块中。
既然 Java SE 平台或 JDK 中没有 CORBA 支持,那么就没有理由包含来自 JTA 的 CORBA 互操作包或来自 J2EE 活动服务的活动包。
综上所述,随着技术的发展和标准的演变,一些旧的或特定于特定应用的技术(如 CORBA)在 Java 中的使用正在减少或被替代。现代 Java 开发更倾向于使用更新、更通用和更易于维护的解决方案,这也是为什么一些旧的或特定于特定应用的 API 和模块在最新的 Java 版本中可能不再被支持或推荐的原因。
描述
在 Java SE 9 中,包含 Java EE 和 CORBA 技术的 Java SE 模块被标记为 建议移除的过时模块,表明在将来的版本中计划移除它们:
java.xml.ws
(JAX-WS,以及相关技术 SAAJ 和 Web Services Metadata)java.xml.bind
(JAXB)java.activation
(JAF)java.xml.ws.annotation
(Common Annotations)java.corba
(CORBA)java.transaction
(JTA)
在 Java SE 9 中,相关的模块也被标记为建议移除的过时模块:
java.se.ee
(上述六个模块的聚合模块)jdk.xml.ws
(JAX-WS 的工具)jdk.xml.bind
(JAXB 的工具)
将模块标记为建议移除的过时模块仅仅会导致编译时警告,为了让开发者更好地为这些模块在未来的版本中实际被移除做好准备,JDK 9 采取了更稳健的步骤:在编译或运行类路径上的代码时,不解析 JDK 运行时映像中的模块(The modules in the JDK runtime image were not resolved when compiling or running code on the class path)。这允许 JDK 9 上的开发者像 JDK 8 一样在类路径上部署 Java EE 和 CORBA 技术的独立版本。或者,JDK 9 上的开发者可以使用命令行上的 --add-modules
来解析 JDK 运行时映像中的模块。
这些改变有助于确保 Java 平台在持续发展中保持其现代化和适应性,同时为新技术的引入和旧技术的逐步淘汰提供了平滑的过渡。开发者需要密切关注这些变化,并根据需要更新他们的代码和依赖关系,以确保他们的应用程序与最新的 Java 版本兼容。
在 Java SE 11 中,上述列出的九个模块将被移除:
它们的源代码将从 OpenJDK 仓库中删除。
它们的类将不再存在于 JDK 运行时映像中。
它们的工具将不再可用:
wsgen
和wsimport
(来自jdk.xml.ws
)schemagen
和xjc
(来自jdk.xml.bind
)idlj
、orbd
、servertool
和tnamesrv
(来自java.corba
)
JNDI 的
CosNaming
提供程序(来自java.corba
)将不再可用。不再有任何命令行标志能够启用这些模块,就像 JDK 9 中的
--add-modules
那样。
rmic
编译器将更新以移除 -idl
和 -iiop
选项。因此,rmic
将不再能够生成 IDL 或 IIOP 存根和绑定类。
JDK 文档 和手册页将更新以移除对这些模块和工具的任何引用,并指示 rmic
的变化。
这一系列的改变是 Java 平台现代化进程的一部分,旨在减少不必要的复杂性和维护负担,同时鼓励开发者使用更加现代和广泛支持的技术。随着这些模块的移除,开发者需要确保他们的代码不再依赖这些被移除的功能,并寻找替代方案来满足他们的需求。同时,JDK 文档和手册页的更新将有助于开发者理解这些变化,并顺利地进行过渡。
测试
所有 JDK、JCK 和 SQE 测试,这些测试涉及到 Java EE 或 CORBA API,都将被移除。
风险与假设
Java EE 模块
移除 Java EE 模块的风险在于,如果应用程序依赖于 JDK 对 Java EE API 和工具的“开箱即用”支持,那么这些应用程序将无法编译或运行。在从 JDK 6、7 或 8 迁移到 JDK 9 或更高版本时,这些应用程序将遇到二进制和源代码的不兼容问题。一般来说,这些应用程序可以分为以下两类:
独立的程序,这些程序在 Java EE 应用服务器之外操作 Web 服务和 XML。
与 Web 服务或 XML 无关的应用程序,但依赖于 Java EE API 中的单个类进行通用功能。例如,一些应用程序依赖 JAXB 并不是为了 XML 绑定,而是为了
javax.xml.bind.DatatypeConverter
类提供的 Base64 支持(从历史上看,这个类比sun.misc.Base64{Encoder,Decoder}
类更好,尽管 Java SE 8 中引入的java.util.Base64
类更好)。另一个例子是,一些应用程序依赖@Generated
注解,其类型javax.annotation.Generated
与 JDK 9 中的 JAX-WS 共存(应用程序也可以选择依赖 Java SE 9 中引入的javax.annotation.processing.Generated
类型)。
为了缓解这些风险,开发者需要:
- 检查他们的代码库,以识别对即将移除的 Java EE 模块的任何依赖。
- 更新代码以使用替代的 API 或库,例如 Java SE 8 或更高版本中引入的 API。
- 确保在迁移到更高版本的 JDK 之前,充分测试应用程序以确保兼容性和功能。
此外,开发者和组织应该意识到,Java EE 技术的未来可能会朝着云原生和微服务架构的方向发展,这可能需要他们采用新的框架和工具集。因此,长期规划和战略决策也是减少风险的关键因素。
CORBA 模块
移除 CORBA 模块可能会对那些仍然依赖 CORBA 进行分布式通信的应用程序产生风险。这些应用程序可能会遇到与 Java EE 模块类似的二进制和源代码不兼容问题。此外,由于 CORBA 是一个较老的技术,其维护和更新可能不再得到广泛支持,因此这些应用程序可能面临更大的技术风险。
为了缓解这些风险,开发者应该:
- 评估他们的应用程序是否真的需要 CORBA,或者是否有更现代、更广泛支持的替代方案。
- 如果确实需要 CORBA,考虑使用第三方库或维护自己的版本,而不是依赖 JDK 中的实现。
- 更新代码以使用替代的通信机制,例如 RESTful API、gRPC 或消息队列等。
最后,对于任何移除的模块或功能,JDK 社区都会尽力通过文档、迁移指南和社区支持来提供帮助,以确保开发者能够平滑地过渡到新的版本。然而,开发者仍然需要承担起责任,确保他们的应用程序与最新的 JDK 版本保持兼容,并遵循最佳实践来减少潜在风险。
移除 Java EE 模块的另一风险是,那些已经从 JDK 6、7 或 8 迁移到 JDK 9 的应用程序,如果它们使用了命令行标志 --add-modules java.se.ee
、--add-modules java.xml.bind
等,将无法启动。
这个提议假设希望在最新的 JDK 上编译或运行应用程序的开发者能够找到并部署 Java EE 技术的替代版本。JAX-WS 和 JAXB 的参考实现(RIs)是一个很好的起点,因为它们分别是 JDK 9 中 java.xml.ws
和 java.xml.bind
模块的完整替代。这些 RIs 可作为 Maven 构件使用(注意它们必须部署在类路径上):
com.sun.xml.ws:jaxws-ri(JAX-WS,以及 SAAJ 和 Web Services Metadata)
com.sun.xml.bind:jaxb-ri(JAXB)
JAX-WS 和 JAXB 的工具也作为 Maven 构件提供:
wsgen
和wsimport
:com.sun.xml.ws:jaxws-tools,以及 工具脚本schemagen
和xjc
:com.sun.xml.bind:jaxb-jxc 和 com.sun.xml.bind:jaxb-xjc,以及 工具脚本
为了顺利迁移并避免潜在风险,开发者应确保:
- 仔细评估应用程序对即将移除的模块的依赖,并确定合适的替代方案。
- 更新项目构建配置(如 Maven 或 Gradle 文件),以包含必要的替代构件作为依赖项。
- 验证替代构件的兼容性,并测试应用程序以确保功能不变和性能可接受。
此外,考虑到 Java EE 技术未来的发展方向,开发者还可以考虑采用更加现代和轻量级的框架和库,以满足应用程序的需求。这可能需要一些重构和学习新技术的投资,但长远来看,将有助于保持应用程序的技术领先性和可维护性。
总之,对于依赖于 Java EE 模块的开发者和组织来说,了解这些变化、制定迁移计划并提前做好准备是至关重要的。
除了包含完整实现的 Maven 构件外,还有一些仅包含 Java EE 技术 API 的 Maven 构件可供使用。这些 API 构件允许开发者在编译时引用 Java EE 的接口和类,而无需包含完整的实现。这对于那些希望在运行时使用特定于提供商的实现或需要保持轻量级依赖的应用程序来说非常有用。
以下是这些 API 构件的 Maven 坐标:
javax.xml.ws:jaxws-api(JAX-WS API,另外还包含 javax.xml.soap:javax.xml.soap-api 用于 SAAJ 和 javax.xml:webservices-api 用于 Web Services Metadata 的 API)
javax.xml.bind:jaxb-api(JAXB API)
javax.annotation:javax.annotation-api(Common Annotations API)
使用这些 API 构件时,开发者需要在项目的构建配置中声明依赖,并确保在编译时这些依赖是可用的。然而,请注意,这些 API 构件不包含实现代码,因此在运行时,您需要确保有相应的实现库在类路径上,以提供 API 所需的具体功能。这通常是通过添加之前提到的参考实现(RIs)或特定提供商的实现作为运行时依赖来完成的。
总之,选择使用 API 构件还是完整的参考实现取决于您的具体需求。如果您只是想在编译时确保类型安全并减少依赖项的大小,那么 API 构件可能是更好的选择。但如果您需要完整的功能支持并且不关心依赖项的大小,那么使用参考实现可能更为合适。
在这个 JEP(Java Enhancement Proposal)实施后,这些 API JAR 文件可以被部署到类路径(class path)上,就像它们在 JDK 8 和 JDK 9 上一样。同时,它们也可以被部署到模块路径(module path)上,这样模块化应用(modular applications)就可以通过 requires
指令来依赖它们。
JAX-WS、JAXB 和 SAAJ 的 API JAR 文件是明确命名的模块,分别叫做
java.xml.ws
、java.xml.bind
和java.xml.soap
。Web Services Metadata 的 API JAR 文件是一个自动模块,命名为
webservices.api
(这个名称来源于 JAR 文件的名称,因为 JAR 清单中还没有更新Automatic-Module-Name
属性)。JAF 和 Common Annotations 的 API JAR 文件是自动模块,分别叫做
java.activation
和java.annotation
(这些名称在 JAR 清单的Automatic-Module-Name
属性中指定)。
在 JDK 9 中,描述中提到的所有模块(除了 java.se.ee
聚合器模块)都是可升级的(upgradeable)。这意味着使用 --add-modules java.xml.bind
等参数的 JDK 9 开发者可以选择依赖 JDK 运行时映像中的 Java EE 模块,或者通过在“升级模块路径”(upgrade module path)上部署 API JAR 文件来覆盖它们。请注意,这里涉及到的是“升级模块路径”而不是模块路径;在 JDK 9 上,即使在使用了 --add-modules java.xml.bind
等参数的情况下,将 API JAR 文件部署到模块路径上也不会有任何效果,因为 JDK 运行时映像中的 Java EE 模块会优先于模块路径上具有相同名称的模块。在这个 JEP 实施后,Java EE 模块将不会存在于 JDK 运行时映像中,因此开发者可以将 API JAR 文件部署到模块路径上。
关于 CORBA 和 JTA 模块,移除 java.corba
模块的风险主要有以下几点:
如果 CORBA 实现只包含了一部分“认可”的 CORBA API,并期望 JDK 提供剩余部分,那么这些实现将无法编译或运行。
使用 RMI-IIOP 的应用程序和 CORBA 实现也将无法编译或运行。RMI-IIOP 包(
javax.rmi
和javax.rmi.CORBA
)位于java.corba
模块中,并与其中的 CORBA 实现绑定。因此,一旦java.corba
被移除,Java SE 中将不再支持 RMI-IIOP。使用
javax.activity
包的应用程序和 CORBA 实现也将无法编译或运行。这个包同样位于java.corba
模块中,并与其中的 CORBA 实现绑定。因此,一旦java.corba
被移除,Java SE 中将不再支持该包。
至于 CORBA 的独立版本,除非第三方接管 CORBA API、ORB 实现、CosNaming 提供程序等的维护工作,否则将不会有独立的 CORBA 版本。由于 Java SE 平台认可 CORBA 的独立实现,第三方维护是可能的。相比之下,RMI-IIOP 的 API 定义和实现完全在 Java SE 内部,除非启动专门的 JSR 来维护它,或者 Eclipse Foundation 接管该 API 的维护,否则将不会有独立的 RMI-IIOP 版本。
最后,关于 J2EE Activity Service,也没有独立的版本。
请注意,上述内容是基于 Java 平台的发展历史和当前状况的分析,实际情况可能会因 Java 平台的更新和第三方社区的动态而有所变化。如果需要最新信息,建议查阅最新的 Java 文档或关注相关社区和论坛的讨论。
关于 JTA 模块,确实存在一个独立的 JTA 版本,可以作为 Maven 构件来使用,即 javax.transaction:javax.transaction-api
。这个 JAR 文件包含了 JTA 的实现,并且根据描述,JTA 1.2 包含了 XA 包和 CORBA 互操作包。而在 2018 年初,JTA 1.3 的定义将只包含 CORBA 互操作包,JAR 文件也会相应地更新。
关于 JTA 1.2 和 JTA 1.3 的 JAR 文件的部署方式,可以总结如下:
JTA 1.2 的 JAR 文件可以部署在类路径(class path)上。JAR 文件中的 XA 包会被忽略,因为
java.sql
模块中的 XA 包会被优先使用。而 JAR 文件中的 CORBA 互操作包则会优先于java.transaction
模块中的包被使用,因为在 JDK 9 中,java.transaction
模块默认不会被解析。需要注意的是,如果在 JDK 9 上使用了--add-modules java.se.ee
或--add-modules java.transaction
选项,那么 JAR 文件中的 CORBA 互操作包会被忽略,而java.transaction
模块中的包会被优先使用。JTA 1.2 的 JAR 文件不能部署在模块路径(module path)上。如果这样做,它会被当作一个包含 XA 包的自动模块来处理,但是这个包会与
java.sql
模块中的 XA 包发生冲突。JTA 1.3 的 JAR 文件可以部署在类路径上。JAR 文件中的 CORBA 互操作包会优先于
java.transaction
模块中的包被使用,因为在 JDK 9 中,java.transaction
模块默认不会被解析。JTA 1.3 的 JAR 文件也可以部署在模块路径上,并作为一个名为
java.transaction
的自动模块来使用。在这种情况下,它会提供 JTA 的功能,并与其他模块进行交互。
这样的设计允许开发者灵活地选择使用哪个版本的 JTA,并且根据项目的需求选择部署在类路径还是模块路径上。同时,它也确保了与 JDK 其他部分的兼容性,特别是在处理 XA 事务和 CORBA 互操作时。