Java模块化规范之争(转载)
经过近20年的发展,Java语言已成为今日世界上最成功、使用的开发者人数最多的语言之一,Java世界中无数商业的或开源的组织、技术和产品共同构成了一个无比庞大的生态系统。
与大多数开发人员的普遍认知不同,Java的生态系统和演进路线并不是由Sun Microsystems公司来决策和管理的。虽然Sun公司拥有“JavaTM”这个商标的所有权,并且拥有Java中使用最广泛的HotSpot虚拟机和Sun JDK,但它并不能直接制定Java世界中的规则、确定Java技术的发展走向。
1998年,在Sun公司的推动下成立了JCP(Java Community Process)组织,这个组织负责制定Java的技术标准,发布技术标准的参考实现(RI)和用于检验标准的技术兼容包(TCK)。目前,除了Sun(目前是Oracle继承了Sun的席位)公司外,还有Google、IBM、Motorola、Nokia、Sybase、SAP等数以百计的公司、组织和独立个人参与了JCP组织,共同监督和维护Java标准的制定。这些参与者中的16位代表组成了JCP执行委员会(JCP Executive Committees,一共有两个这样的委员会,分别对应Java SE/EE方向和Java ME方向),对提交给JCP的提案进行投票表决。
JCP允许任何组织或个人对Java的演进路线提出建议,这些建议在审查立项后会以JSR(Java Specification Requests)的形式形成正式的规范提案文档;在经过专家组审核和执行委员会投票通过之后,这些JSR文档就将成为正式的Java技术规范。J2EE、EJB、JSP、JDBC、JMX、JVMS等规范都由对应的JSR文档“孵化”而来,甚至连JCP本身的组织和运作方式也是由特定的JSR文档进行定义的。
以上介绍的内容虽然与OSGi没有直接关系,但是它们是读者了解后面介绍的OSGi与Java之间关系的必要背景知识。
OSGi源于JSR-8(Open Services Gateway Specification,开放服务网关规范),这是一份由Sun发起并主导(共同发起的还有IBM、Ericsson和Sybase等公司)、在1999年3月提交到JCP的规范提案。这份规范定义了不同设备之间服务互相依赖和调用的交互接口。1999年,Java 2刚发布不久,互联网也刚刚兴起,“支持各种移动设备、嵌入式设备、智能家电”这个最初建立Java语言的目标,对于Java来说依然是最重要领域之一。
不过,JSR-8提案很快(1999年5月,即提交之后的2个月)就被发起者撤回。撤回并不是因为这份JSR不够资格成为Java规范发布,主要是发起者希望另外建立一个独立于JCP的组织来发展运作这份规范,让更多不适合参与到JCP的设备厂商能够参与OSGi的规范制定。因此,1999年独立于JCP的OSGi联盟成立,并于2000年发布了OSGi规范的第一个版本:OSGi R1.0。
在OSGi的前三个版本中,OSGi主要领域依然维系在移动和嵌入式设备之上,在这三个版本的发展中Sun公司起了很大的推动作用,这段时间可谓是OSGi和Sun的蜜月期。比如Sun的JES(Java Embedded Server)就是当时使用最广泛的OSGi R2的实现。从OSGi R4开始,OSGi开始尝试跨越移动和嵌入式领域的限制,进入Java SE/EE领域,与此同时,OSGi联盟的各个成员在发展和商业选择上也产生了分歧,各自(主要是IBM和Sun)都在争夺OSGi联盟的主导权。在这个过程中各厂商是如何争夺规范控制权的我们不得而知,总之最终的结果是Sun公司于2006年离开了当年它一手主导建立的OSGi联盟。OSGi规范分为面向Java主流领域的OSGi R4核心规范和依然专门面向嵌入式和移动领域的OSGi移动设备规范(即JSR-232 Mobile Operational Management,OSGi R4 Mobile与JSR-232的内容是完全一致的)。
在今天看来,Sun的离开恰恰证明了当时它在Java模块化方向上的错误。OSGi R4的目标平台转变为Java SE/EE,进军桌面、服务端和互联网的举措获得了很大的成功,关于这点不得不提到在IBM支持下Eclipse基金会对OSGi快速流行所做出的贡献。自Eclipse 3.0 M4版本开始,这款著名的集成开发工具被重构为完全基于OSGi架构实现的产品,支持Eclipse运行的底层框架Equinox成为OSGi R4.x使用最广泛的实现框架。伴随着Eclipse IDE的流行,OSGi迅速在Java ME以外的领域站稳脚跟。许多人(包括笔者)都是从Eclipse开始关注OSGi的,IBM的很多后续产品,如WebSphere、JAZZ等都继续支持OSGi或直接基于OSGi来构建,其他公司也迅速跟进。
OSGi R4的迅速流行带来一个强烈的信号:Java SE/EE支持模块化已经成为一股不可逆转的潮流,支持模块化的呼声已经强大到令Sun公司不能再忽视的程度。Sun公司期望能借助JCP的力量重新争夺Java模块化规范的控制权。
2006年10月,由Sun公司提交的JSR-277规范提案(Java Module System,Java模块化系统)发布了第一个早期预览版(Early Draft Review);2007年年底,Sun携带着JSR-277重新加入OSGi联盟。
JSR-277是一个全静态的模块化规范,它在模块化和依赖描述方面与OSGi有着相似的能力,在构建模块仓库(Repository)上对比当时的OSGi规范占有一定优势(OSGi这方面的弱点在2012年7月OSGi R5发布并拥有了Subsystem Service和Repository Service之后已经被填补)。但是JSR-277是完全静态的,没有任何关于动态化的考虑,这样模块就无法在运行时安装、更新和卸载,因此也就不存在类空间一致性、类和类加载器卸载等问题。这点相对于OSGi的动态模块化来说是极大的退步。另外JSR-277引入新的“.jam”格式文件作为模块分发格式也被大家所诟病。OSGi技术专家、OSGi联盟主席Peter Kriens在OSGi联盟的官方博客上发表文章批评道:“JSR-277的目标如同儿戏,只能相当于OSGi在8年前的技术水平”。
在JCP中争夺模块化规范控制权,对于Sun来说会比在OSGi联盟中更为有利。Sun在JCP拥有很大的影响力,它是JCP的发起者,担任JCP的主席,在执委会中拥有无须选举的无限期执委会投票权(其他15个执委席位三年选举一次),Sun肯定希望能永远保持在JCP中的领导地位,但是JCP的其他成员都希望能够在Java的规范和发展路线上拥有更大的话语权。这样,不可避免会产生一些利益冲突。Sun力挺JSR-277,希望用它代替OSGi成为Java模块化标准,IBM则将OSGi R4.1提交到JCP成为JSR-291(Dynamic Component Support for Java SE ,Java SE动态组件支持)来与JSR-277对抗,这样,在OSGi联盟中的规范之争的战场又重新回到JCP之中。
这两个JSR竞争的结果是JSR-277没有得到通过,尽管Sun曾经做出了一些让步,比如承诺JSR-277可以引用和操作OSGi的遗留模块,它最终还是没有得到足够的支持,被废止在早期预览版阶段。另一方面,在对JSR-291进行表决时,虽然Sun明确投了反对票,但是JSR-291仍然在JCP执委会最终投票中通过。这样,OSGi终于确立了Java唯一的模块化规范的地位。不过,事情并没有结束,JSR-291得到通过并不意味着OSGi规范立刻就会成为现实。
虽然OSGi R4.1在2007年5月通过投票之后就应该是正式的Java规范,但是Sun依然在JSR-316(Java Platform, Enterprise Edition 6 Specification,Java企业版规范第6版,这个规范提案在2007年7月提交给JCP,2009年12月发布最终版,提交时JSR-277与JSR-291之争已尘埃落定)的规范目标中明确写道:“为了更好地支持这个平台(指Java EE 6)在扩展性方面的目标,应该有一个更加宽泛的模块化概念。这项工作正由‘JSR-277 Java模块系统’来实现,它的目标平台是Java SE 7。我们预期Java EE 7将建立在这项技术的基础上,因此我们将推迟任何可能与将来的版本冲突的技术规范”。在这段话中所谓的“可能与将来的版本冲突的技术规范”毫无疑问就是JSR-291了。Sun(当时已经被Oracle收购了)这种一意孤行地坚持自己的JSR-277而无视JSR-291的行为招来了许多非议。但是非议无法解决问题,Sun仍然实质性地控制着JDK的发展,最终结果就如JSR-316中的那句话所表达的那样,整个Java SE 6期间没有任何模块化相关的改进以JDK功能的形式进入到Java平台中。Sun对待OSGi的态度不应解读为Sun反对Java模块化,相反,这是Sun极为重视Java模块化的体现,它一定要把Java模块化的主导权抓在手中。尽管Sun的做法拖延了Java模块化的进程,但模块化依然是不可避免地向前发展了,到Java SE 7中又如何呢?
讲到Java SE 7的模块化,我们不得不再多介绍一个规范提案:JSR-294(Improved Modularity Support in the Java Programming Language,Java语言的模块化改进)。如此之多(提交的时间很集中,并且是并行发展的,在JSR-294提交时JSR-277并没有被废止)的JSR来解决重复的问题在JCP历史上也是极为罕见的。这个规范提案的提交者也是Sun公司,它试图在Java语言和Java虚拟机层面上对模块化进行支持,直接修改JLS(Java语言规范)和JVMS(Java虚拟机规范),加入module关键字和超级包(Super Package)等概念。JSR-294的模块化实现思想与OSGi的差异是非常大的,通俗地讲,OSGi是在Java平台之上建立的模块化,而JSR-294是直接在Java平台之内建立的模块化。
从纯粹技术角度来看,Java模块化如果真能通过直接修改Java语法、Class文件格式和Java虚拟机来实现,我们相信这种实现方案的性能、完善程度肯定能够超越OSGi,仅从技术角度看,这种改进方式无疑是Java模块化的最佳结果。不过,修改Java语法在JCP中历来都是“慎重而敏感的话题”,增加新的语言特性相对缓慢,这点也是社区管理的劣势。对比一下微软一家单独掌控的C#语言,就能看出明显差距。
话题再回到JSR-294,很遗憾,这个规范提案的结果与JSR-277一样,也被废弃在早期预览版阶段。Sun似乎早就预料到这个结果,它在提交JSR-294的同时,就在OpenJDK中启动了Jigsaw项目的孵化进程。Jigsaw项目最开始的目标是作为JSR-294的参考实现(RI),但是该项目的开发过程却是在jigsaw-dev邮件列表上进行的,该邮件列表游离于JSR-294专家组的邮件列表之外。目前的种种迹象表明,Sun决定让Jigsaw项目采取“SunJDK专有的方式”来实现Java语言模块化,JSR-294没有得到通过,也就意味着Jigsaw项目是Sun私有的,使用了Jigsaw的Java程序无法运行于其他公司提供的JDK之上。因此,即使Jigsaw本身的设计再好,只要无法做到“一次编译,到处运行”的模块化,就必然是对Java语言最重要一块基石的巨大损害。
很难相信Sun最后会以私有化的方式强行推出Jigsaw,这是非常不明智的。最后的结果肯定还要重新激活JSR-294,或者再提交另外一个JSR使之在JCP上通过,在此之前,Jigsaw只能无限期拖延下去。目前Jigsaw已经拖得足够长了,最初它是作为Java SE 7的特性进行设计的,后来因Java 7进度压力被推迟到Java 8之中,在2012年7月,在Jigsaw项目的主页上宣布它将进一步被延迟到Java 9中发布。这样导致的结果是,即使后续一切顺利,用户也要到2015年9月才能见到Jigsaw,那时已经是OSGi出现的16年之后了;再等到Java 9被应用到主流的生产环境中,Jigsaw就显得更加遥遥无期了。如果系统要兼容Java 2至Java 8平台,OSGi还是唯一的选择。Jigsaw不得不正视OSGi事实上的模块化规范的地位,建立了一个名为的Penrose子项目让Jigsaw可以与OSGi互相操作。
目前OSGi是Java世界中唯一的模块化规范,从纯技术角度看,它未必是最先进的模块化技术,从学习使用来看,它也不是使用最简单方便的模块化技术。但是从整个Java业界整体来看,OSGi确实是过去、现在乃至未来至少5年内可预见的最有生命力、最标准、使用范围最广泛的Java模块化技术。随着Java应用规模的日益庞大,越来越多的大型系统使用OSGi架构进行建设,因此,OSGi是具有广阔发展前景和使用、学习价值的。