为什么项目拼图/ JPMS?
Java的包pipe理系统对我来说总是显得简单而有效。 它被JDK本身大量使用。 我们一直在用它来模仿名称空间和模块的概念。
什么是项目拼图 (又名Java平台模块系统 )试图填写?
来自官方网站:
本项目的目标是为Java SE平台devise和实现标准模块系统,并将该系统应用于平台本身和JDK。
Jigsaw和OSGi正试图解决同样的问题:如何让粗粒度的模块在屏蔽内部的同时进行交互。
在拼图的情况下,粗粒度模块包括Java类,包和它们的依赖关系。
下面是一个例子:Spring和Hibernate。 两者都依赖于第三方JAR CGLIB,但是它们使用该JAR的不同的不兼容版本。 如果你依赖于标准的JDK,你能做什么? 包括Spring要破解的版本,反之亦然。
但是,如果你有像Jigsaw这样的更高级的模型,你可以很容易地在不同的模块中pipe理不同版本的JAR。 把它们想象成更高级别的包。
如果你从GitHub源码构buildSpring,你也会看到它。 他们已经重做了框架,所以它由几个模块组成:核心,持久性等等。你可以select你的应用程序需要的最小的一组模块依赖项,并忽略其余部分。 它曾经是一个单独的Spring JAR,其中包含了所有的.class文件。
更新:五年后 - 拼图可能还有一些问题需要解决。
AFAIK计划是使JRE更加模块化。 即有较小的可选的jar子和/或只能下载/升级所需的function。
它使它不那么臃肿,并让您select丢弃也许大多数人不使用的遗留模块。
基于Mark Reinhold 在比利时Devoxx的主题演讲 , Jigsaw项目将解决两个主要问题:
- 类path
- 大规模的单片JDK
Classpath出了什么问题?
我们都知道JAR地狱 。 这个术语描述了类加载过程最终可能失效的所有方式。 classpath最有名的限制是:
- 很难判断是否有冲突。 像maven这样的构build工具可以根据工件名称做出相当不错的工作,但是如果工件本身具有不同的名称但内容相同,则可能会有冲突。
- jar文件的根本问题是它们不是组件。 他们只是一堆文件容器,将被线性search。 类path是查找类的一种方式,不pipe他们在什么组件,他们在什么包或者他们的预期用途。
大规模的单片JDK
JDK的巨大的单一性质导致了几个问题:
- 它不适合小型设备。 即使小IoTtypes的设备具有能够运行SE级VM的处理器,但是它们并不一定具有容纳所有JDK的内存,特别是当应用程序仅使用其中的一小部分时。
- 这在云端甚至是一个问题。 云是关于优化硬件的使用,如果你有成千上万的包含整个JDK的图像,但应用程序只使用它的一小部分,这将是一种浪费。
模块:通用解决scheme
为了解决上述问题,我们将模块作为一种基本的新型Java程序组件来处理。 一个模块是一个命名的,自描述的代码和数据集合。 其代码被组织为一组包含types的包,即Java类和接口; 其数据包括资源和其他types的静态信息。
为了控制其代码如何引用其他模块中的types,模块会声明它需要哪些其他模块才能编译和运行。 要控制其他模块中的代码如何引用其包中的types,模块会声明它导出哪些包。
模块系统定位所需的模块,并且与类path机制不同,确保模块中的代码只能引用它所依赖的模块中的types。 Java语言和Java虚拟机的访问控制机制阻止代码访问未被定义模块导出的包中的types。
除了更可靠,模块化可以提高性能。 当模块中的代码引用包中的types时,那么该包将保证在该模块中定义,或者只在该模块读取的模块中定义一个。 因此,在查找特定types的定义时,不需要在多个模块中进行search,更不用说在整个课程path中进行search。
JEP要遵循
拼图是一个持续了好几年的巨大项目。 它有一个令人印象深刻的JEP数量,这是获得有关该项目更多信息的好地方。 其中一些JEP如下所示:
- JEP 200:模块化JDK : 使用Java平台模块系统(JPMS)模块化JDK
- JEP 201:模块化源代码 : 将JDK源代码重组为模块,增强构build系统以编译模块,并在构build时强制执行模块边界
- JEP 261:模块系统 : 按照JSR 376的规定实现Java平台模块系统,以及相关的JDK特定更改和增强
- JEP 220:模块化运行时映像 : 重构JDK和JRE运行时映像以适应模块并提高性能,安全性和可维护性
- JEP 260:封装大多数内部API : 默认情况下,大部分JDK的内部API是不可访问的,但是可以使用一些关键的,广泛使用的内部API,直到支持所有或大部分function的replace
- JEP 282:jlink:Java链接器 : 创build一个工具,可以将一组模块及其依赖关系组合并优化为JEP 220中定义的自定义运行时映像
结束语
在“ 模块系统状态”报告的最初版本中,Mark Reinhold将模块系统的具体目标描述如下:
- 可靠的configuration ,用程序组件相互声明显式依赖的方法replace脆弱的,容易出错的类path机制,以及
- 强大的封装 ,允许组件声明其中哪些公共types可以被其他组件访问,哪些不是。
这些function将直接或间接地使应用程序开发人员,库开发人员和Java SE平台自身的实现者受益,因为他们将实现可扩展的平台,更高的平台完整性和更高的性能。
为了说明起见,让我们断言Java 8(及更早版本) 已经具有模块(jar)和模块系统(classpath)的“forms”。 但是这些问题都有众所周知的问题。
通过检查问题,我们可以说明拼图的动机。 (以下假设我们没有使用OSGi,JBoss模块等,这当然提供了解决scheme。)
问题1:公众太公开
考虑以下类别(假设都是公开的):
com.acme.foo.db.api.UserDao com.acme.foo.db.impl.UserDaoImpl
在Foo.com,我们可能会决定我们的团队应该使用UserDao
而不是直接使用UserDaoImpl
。 但是,在类path上没有办法强制执行。
在Jigsaw中,一个模块包含一个module-info.java
文件,它允许我们明确地声明对其他模块公开的内容。 也就是说,公众有细微差别。 例如:
// com.acme.foo.db.api.UserDao is accessible, but // com.acme.foo.db.impl.UserDaoImpl is not module com.acme.foo.db { exports com.acme.foo.db.api; }
问题2:反思是肆无忌惮的
鉴于#1中的类,有人仍然可以在Java 8中做到这一点:
Class c = Class.forName("com.acme.foo.db.impl.UserDaoImpl"); Object obj = c.getConstructor().newInstance();
也就是说:reflection是强大的和必不可less的,但是如果不加以限制的话,它可以用来以不希望的方式进入模块的内部。 马克·莱因霍尔德有一个相当惊人的例子 。 (SOpost在这里 )
在拼图中, 强封装提供拒绝访问类的能力,包括反思。 (这可能取决于命令行设置,等待JDK 9的修订技术规范。)请注意,由于Jigsaw本身被用于JDK,因此Oracle声称这将使Java团队能够更快地创新平台内部。
问题3:类path会擦除架构关系
一个团队通常有一个关于jar子之间关系的心理模型。 例如, foo-app.jar
可以使用使用foo-db.jar
。 我们可能会断言foo-app.jar
中的类不应该绕过“服务层”并直接使用foo-db.jar
。 但是,没有办法通过classpath来强制执行。 马克·莱因霍尔德在这里提到。
相比之下,Jigsaw为模块提供了一个明确,可靠的可访问模型。
问题4:单片运行时间
Java运行时在单片rt.jar
。 在我的机器上,有20k类的60+ MB! 在微服务,物联网设备等时代,如果不使用Corba,Swing,XML和其他磁带库,则不太可能。
拼图将JDK本身分解成许多模块; 例如java.sql包含熟悉的SQL类。 这有几个好处,但一个新的是jlink
工具。 假设一个应用程序是完全模块化的, jlink
生成一个可分发的运行时图像 ,该图像被修剪为仅包含指定的模块(及其依赖关系)。 outlook未来,Oracle 设想将JDK模块提前编译成本地代码。 尽pipejlink
是可选的,而且AOT汇编是实验性的,但它们是甲骨文领导的主要标志。
问题5:版本控制
众所周知,classpath不允许我们使用同一个jar的多个版本:例如bar-lib-1.1.jar
和bar-lib-2.2.jar
。
拼图没有解决这个问题。 马克·莱因霍尔德(Mark Reinhold)在这里说明了理由 要点在于,Maven,Gradle和其他工具代表了一个依赖pipe理的庞大生态系统,另一个解决scheme将会更有害无益。
应该指出的是,其他解决scheme(如OSGi)确实解决了这个问题(除了#4之外的其他解决scheme)。
底线
由于具体问题,这是拼图的一些关键点。
请注意,解释Jigsaw,OSGi,JBoss Modules等之间的争议是属于另一个Stack Exchange站点的单独讨论。 解决scheme之间有更多的差异比这里描述的。 此外,还有足够的共识来批准JSR 376的公众评议复议投票 。
本文详细解释了OSGi和JPMS / Jigsaw试图解决的问题:
“Java 9,OSGi和模块化的未来” [2016年9月22日]
它也深入到OSGi和JPMS / Jigsaw的方法。 到目前为止,看起来作者列出的JPMS /拼图几乎没有实用的优点与成熟(16岁)OSGi相比。