Java的程序包管理系统对我而言似乎总是简单而有效的。JDK本身大量使用它。我们一直在使用它来模仿名称空间和模块的概念。
什么是Jigsaw项目(又名Java平台模块系统)试图填补?
从官方网站:
该项目的目标是为Java SE平台设计和实现标准模块系统,并将该系统应用于平台本身和JDK。
Java的程序包管理系统对我而言似乎总是简单而有效的。JDK本身大量使用它。我们一直在使用它来模仿名称空间和模块的概念。
什么是Jigsaw项目(又名Java平台模块系统)试图填补?
从官方网站:
该项目的目标是为Java SE平台设计和实现标准模块系统,并将该系统应用于平台本身和JDK。
Answers:
Jigsaw和OSGi试图解决相同的问题:如何在保护内部组件的同时允许粗粒度模块进行交互。
在Jigsaw的情况下,较粗粒度的模块包括Java类,程序包及其依赖项。
这是一个示例:Spring和Hibernate。两者都依赖于第三方JAR CGLIB,但是它们使用该JAR的不同,不兼容的版本。如果您依赖标准JDK怎么办?包括Spring想要破解Hibernate的版本,反之亦然。
但是,如果您拥有像Jigsaw这样的高级模型,则可以在不同的模块中轻松管理不同版本的JAR。将它们视为更高级别的软件包。
如果您从GitHub源码构建Spring,您也会看到它。他们已经重做了框架,因此它由几个模块组成:核心,持久性等。您可以选择应用程序所需的最小模块依赖项集,而忽略其余部分。它曾经是单个Spring JAR,其中包含所有.class文件。
更新:五年后-拼图可能仍然需要解决一些问题。
AFAIK计划是使JRE更具模块化。即具有较小的jar,它们是可选的,并且/或者您只能下载/升级所需的功能。
它可以减少膨胀,并为您提供删除大多数人可能不使用的旧模块的选项。
import
所有这些方法时,是将该类引入编译器的类的名称空间。如果您实际上不使用它,它将不会出现在创建的字节码中。如果您实际使用该类,则需要该类及其在运行时使用的每个类。从理论上讲,您可以创建仅具有所需内容的guava API的简化版本,而改用该JAR。实际上,这很容易出错,并且在大多数情况下不是很有用,最终您只能添加已发布的整个JAR。
根据Mark Reinhold在比利时Devoxx上的主题演讲,拼图计划将解决两个主要的痛点:
我们都知道JAR地狱。该术语描述了导致类加载过程最终无法正常工作的所有各种方式。类路径的最著名的限制是:
JDK的巨大整体性导致几个问题:
为了解决上述问题,我们将模块视为一种基本的新型Java程序组件。模块是命名的,自描述的代码和数据集合。它的代码被组织为一组包含类型(即Java类和接口)的软件包。其数据包括资源和其他种类的静态信息。
为了控制其代码如何引用其他模块中的类型,模块声明要编译和运行它需要哪些其他模块。为了控制其他模块中的代码如何引用其包中的类型,模块声明要导出的包中的哪个。
模块系统查找所需的模块,并且与类路径机制不同,它确保模块中的代码只能引用其所依赖的模块中的类型。Java语言和Java虚拟机的访问控制机制可防止代码访问其定义模块未导出的程序包中的类型。
除了更可靠之外,模块化还可以提高性能。当模块中的代码引用包中的类型时,则可以保证在该模块中定义该包,或者恰好在该模块读取的一个模块中定义该包。因此,在查找特定类型的定义时,无需在多个模块中或更糟的是在整个类路径中进行搜索。
拼图是一个巨大的项目,已经进行了很多年。它包含大量令人印象深刻的JEP,这些都是获得有关该项目更多信息的好地方。其中一些JEP如下:
在模块系统状态报告的初始版本中,Mark Reinhold描述了模块系统的特定目标,如下所示:
这些功能将直接或间接地使应用程序开发人员,库开发人员和Java SE Platform本身的实现者受益,因为它们将使可伸缩平台,更高的平台完整性和更高的性能成为可能。
为了争辩,我们断言Java 8(及更早版本)已经具有模块(罐)和模块系统(类路径)的“形式”。但是这些都有一些众所周知的问题。
通过研究问题,我们可以说明拼图的动机。(以下假设我们没有使用OSGi,JBoss Modules等,它们肯定会提供解决方案。)
问题一:公众太公开
考虑以下类(假设两者都是公共的):
com.acme.foo.db.api.UserDao
com.acme.foo.db.impl.UserDaoImpl
在Foo.com,我们可能会决定我们的团队应该使用UserDao
而不是UserDaoImpl
直接使用。但是,没有办法在类路径上强制执行该操作。
在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();
就是说:反射是强大且必不可少的,但是如果不加以检查,它可以以不希望的方式用于进入模块的内部。马克·莱因霍尔德(Mark Reinhold)有一个令人震惊的例子。(SO帖子在这里。)
在Jigsaw中,强封装提供了拒绝访问类(包括反射)的能力。(这可能取决于命令行设置,有待修订的JDK 9技术规范。)请注意,由于Jigsaw用于JDK本身,因此Oracle声称这将使Java团队能够更快地创新平台内部。
问题3:类路径消除了架构关系
团队通常具有关于罐子之间关系的心理模型。例如,foo-app.jar
可以使用foo-services.jar
其中的用途foo-db.jar
。我们可能会断言in中的类foo-app.jar
不应绕过“服务层”而foo-db.jar
直接使用。但是,没有办法通过类路径强制执行该操作。马克·莱因霍尔德(Mark Reinhold)在这里提到了这个问题。
相比之下,Jigsaw为模块提供了明确,可靠的可访问性模型。
问题4:整体运行时
Java运行时位于整体中rt.jar
。在我的机器上,它是60+ MB的20k类!在微服务,物联网设备等时代,如果不使用Corba,Swing,XML和其他库,则不希望在磁盘上使用它们。
拼图将JDK本身分为许多模块。例如,java.sql包含熟悉的SQL类。这样做有很多好处,但是一种新的jlink
工具。假设应用程序已完全模块化,则jlink
生成可分发的运行时映像,该映像被裁剪为仅包含指定的模块(及其依赖项)。展望未来,Oracle展望了将JDK模块提前编译为本机代码的未来。尽管jlink
是可选的,并且AOT编译是试验性的,但它们是Oracle前进方向的主要指示。
问题5:版本控制
众所周知,类路径不允许我们使用同一jar的多个版本:egbar-lib-1.1.jar
和bar-lib-2.2.jar
。
拼图没有解决这个问题。马克·雷因霍尔德(Mark Reinhold)在这里陈述了基本原理。要点是,Maven,Gradle和其他工具代表了一个庞大的依赖管理生态系统,而另一种解决方案则弊大于利。
应当注意,其他解决方案(例如OSGi)确实解决了这个问题(除了#4,还有其他解决方案)。
底线
这是拼图的一些关键点,受特定问题的影响。
注意,解释Jigsaw,OSGi,JBoss Modules等之间的争议是一个单独的讨论,它属于另一个Stack Exchange站点。解决方案之间的差异比这里描述的要多得多。而且,已经有足够的共识来批准JSR 376的“公共审核重新审议”投票。
本文详细解释了OSGi和JPMS / Jigsaw都试图解决的问题:
“ Java 9,OSGi和模块化的未来” [2016年9月22日]
它还深入探讨了OSGi和JPMS / Jigsaw的方法。到目前为止,与成熟的OSGi(16岁)相比,作者似乎几乎没有列出JPMS / Jigsaw的实用Pro。