Java的包管理系统对我来说似乎总是简单而有效。 JDK本身大量使用它。我们一直在使用它来模仿命名空间和模块的概念。
什么是 Project Jigsaw (又名Java Platform Module System)试图填写?
来自官方网站:
该项目的目标是设计和实施标准模块 Java SE平台的系统,并将该系统应用于 平台本身和JDK。
答案 0 :(得分:99)
Jigsaw和OSGi正试图解决同样的问题:如何允许粗粒度模块在屏蔽其内部时进行交互。
在Jigsaw的案例中,粗粒度模块包括Java类,包及其依赖项。
这是一个例子:Spring和Hibernate。两者都依赖于第三方JAR CGLIB,但它们使用该JAR的不同,不兼容的版本。如果您依赖标准JDK,您会怎么做?包括Spring想要打破Hibernate的版本,反之亦然。
但是,如果你有像Jigsaw这样的更高级别的模型,你可以轻松地在不同的模块中管理不同版本的JAR。将它们视为更高级别的包。
如果您构建Spring from the GitHub source,您也会看到它。他们重做框架,因此它包含几个模块:核心,持久性等。您可以选择应用程序所需的最小模块依赖项集,而忽略其余部分。它曾经是一个Spring JAR,其中包含所有.class文件。
更新:五年后 - Jigsaw可能还有一些issues要解决。
答案 1 :(得分:43)
AFAIK计划是使JRE更加模块化。即有较小的罐子是可选的和/或你只能下载/升级你需要的功能。
它使它不那么臃肿,让你可以选择丢弃可能大多数人不使用的遗留模块。
答案 2 :(得分:42)
基于Mark Reinhold的keynote speech at Devoxx Belgium, Project Jigsaw 将解决两个主要难点:
我们都知道JAR Hell。该术语描述了类加载过程最终无法正常工作的各种方式。类路径的最常见限制是:
JDK的巨大单一性质导致了几个问题:
为了解决上述问题,我们将模块视为一种基本的新型Java程序组件。模块是一个命名的,自描述的代码和数据集合。它的代码被组织为一组包含类型的包,即Java类和接口;其数据包括资源和其他类型的静态信息。
要控制其代码如何引用其他模块中的类型,模块会声明它需要哪些其他模块才能进行编译和运行。为了控制其他模块中的代码如何引用其包中的类型,模块声明它导出哪些包。
模块系统定位所需的模块,与类路径机制不同,它确保模块中的代码只能引用它所依赖的模块中的类型。 Java语言和Java虚拟机的访问控制机制阻止代码访问未由其定义模块导出的包中的类型。
除了更可靠之外,模块化还可以提高性能。当模块中的代码引用包中的类型时,该包确保在该模块中或在该模块读取的模块中定义。因此,在寻找特定类型的定义时,不需要在多个模块中搜索它,或者更糟糕的是,在整个类路径中搜索它。
在The State of the Module System报告的初始版本中,Mark Reinhold描述了模块系统的具体目标如下:
这些功能将直接和间接地使Java SE平台本身的应用程序开发人员,库开发人员和实现者受益,因为他们将实现可扩展的平台,更高的平台完整性和更高的性能。
答案 3 :(得分:13)
为了论证,让我们断言Java 8(及更早版本)已经 a"形式"模块(jar)和模块系统(类路径)。但是这些都存在众所周知的问题。
通过检查问题,我们可以说明Jigsaw的动机。 (以下假设我们没有使用OSGi,JBoss模块等,它们肯定会提供解决方案。)
问题1:公众太公开
考虑以下类(假设两者都是公共的):
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有一个alarming example。 (SO帖子是here。)
在Jigsaw中,强封装提供拒绝访问类的能力,包括反射。 (这可能取决于命令行设置,等待JDK 9的修订技术规范。)请注意,由于Jigsaw用于JDK本身,Oracle声称这将允许Java团队更快地创新平台内部。
问题3:类路径删除了架构关系
团队通常有关于罐子之间关系的心智模型。例如,foo-app.jar
可能会使用使用foo-services.jar
的{{1}}。我们可能断言foo-db.jar
中的类不应绕过"服务层"并直接使用foo-app.jar
。但是,没有办法通过类路径强制执行。 Mark Reinhold提到了this here。
相比之下,Jigsaw为模块提供了一个明确,可靠的可访问性模型。
问题4:整体运行时间
Java运行时位于单片foo-db.jar
中。在我的机器上,它是60+ MB,20k课程!在微服务,物联网设备等时代,如果不使用Corba,Swing,XML和其他磁盘库,则不宜这样做。
Jigsaw将 JDK本身分解为许多模块;例如java.sql包含熟悉的SQL类。这有几个好处,但新的是rt.jar
工具。假设应用程序完全模块化,jlink
生成一个distributable run-time image,它被修剪为仅包含指定的模块(及其依赖项)。展望未来,Oracle envisions a future将JDK模块提前编译为本机代码。虽然jlink
是可选的,并且AOT编译是实验性的,但它们是Oracle前进的主要指标。
问题5:版本控制
众所周知,类路径不允许我们使用同一个jar的多个版本:例如jlink
和bar-lib-1.1.jar
。
Jigsaw没有解决这个问题;马克·莱因霍尔德说rationale here。要点是Maven,Gradle和其他工具代表了依赖管理的大型生态系统,而另一种解决方案将更有害而不是有益。
应该注意的是,其他解决方案(例如OSGi)确实解决了这个问题(除了#4之外的其他解决方案)。
底线
这是Jigsaw的一些关键点,由特定问题驱动。
请注意,解释Jigsaw,OSGi,JBoss Modules等之间的争议是一个单独的讨论,属于另一个Stack Exchange站点。解决方案之间的差异比此处描述的要多得多。更重要的是,有足够的共识来批准JSR 376的Public Review Reconsideration Ballot。
答案 4 :(得分:3)
本文详细解释了OSGi和JPMS / Jigsaw试图解决的问题:
"Java 9, OSGi and the Future of Modularity" [2016年9月22日]
它也深入研究了OSGi和JPMS / Jigsaw的方法。 截至目前,似乎作者列出了JPMS / Jigsaw与成熟(16岁)OSGi相比几乎没有实用的优点。