为什么要投资Jigsaw/JPMS?

Joh*_*ohn 78 java java-platform-module-system java-9

Java的包管理系统对我来说似乎总是简单而有效.JDK本身大量使用它.我们一直在使用它来模仿名称空间和模块的概念.

什么是Project Jigsaw(又名Java平台模块系统)试图填写?

来自官方网站:

该项目的目标是为Java SE平台设计和实现标准模块系统,并将该系统应用于平台本身和JDK.

duf*_*ymo 100

Jigsaw和OSGi正试图解决同样的问题:如何允许更粗粒度的模块在屏蔽其内部时进行交互.

在Jigsaw的案例中,粗粒度模块包括Java类,包及其依赖项.

这是一个例子:Spring和Hibernate.两者都依赖于第三方JAR CGLIB,但它们使用该JAR的不同,不兼容的版本.如果您依赖标准JDK,您会怎么做?包括Spring想要打破Hibernate的版本,反之亦然.

但是,如果你有像Jigsaw这样的更高级别的模型,你可以轻松地在不同的模块中管理不同版本的JAR.将它们视为更高级别的包.

如果你从GitHub源代码构建Spring,你也会看到它.他们重做框架,因此它包含几个模块:核心,持久性等.您可以选择应用程序所需的最小模块依赖项集,而忽略其余部分.它曾经是一个Spring JAR,其中包含所有.class文件.

更新:五年后 -​​ Jigsaw可能仍有一些问题需要解决.

  • 鉴于实际上将在java 9中发布的内容,这篇文章会产生误导.在编写本文时可能是准确的. (7认同)
  • 如果您仍然需要使用完全相同的模块,但它有两个不同版本,该怎么办?他们不应该只是添加某种支持,所以同一类的两个版本可以共存吗? (5认同)

Pet*_*rey 43

AFAIK计划是使JRE更加模块化.即具有较小的罐子是可选的和/或您可以只下载/升级您需要的功能.

它使它不那么臃肿,并让你选择丢弃可能大多数人不使用的遗留模块.

  • 接受的答案是有效的,但这个答案更好,因为它解释了实际的预期效果.+1,当之无愧. (6认同)

Ali*_*ani 43

根据Mark Reinhold 在Devoxx Belgium主题演讲,Project Jigsaw将解决两个主要难点:

  1. 类路径
  2. 庞大的整体JDK

Classpath有什么问题?

我们都知道JAR地狱.该术语描述了类加载过程最终无法工作的各种方式.类路径的最常见限制是:

  • 很难判断是否存在冲突.像maven这样的构建工具可以根据工件名称做得很好,但如果工件本身具有不同的名称但内容相同,则可能存在冲突.
  • jar文件的根本问题在于它们不是组件.它们只是一堆文件容器,可以线性搜索.Classpath是一种查找类的方法,无论它们在哪个组件中,它们包含哪些包或它们的预期用途.

庞大的整体JDK

JDK的巨大整体性质导致了几个问题:

  • 它不适合小型设备.即使小型物联网类型设备具有能够运行SE类VM的处理器,但它们不一定拥有容纳所有JDK的存储器,尤其是当应用程序仅使用它的一小部分时.
  • 这甚至是云中的一个问题.云就是优化硬件的使用,如果你有成千上万的图像包含整个JDK但应用程序只使用它的一小部分,那将是一种浪费.

模块:通用解决方案

为了解决上述问题,我们将模块视为一种基本的新型Java程序组件.模块是一个命名的,自描述的代码和数据集合.它的代码被组织为一组包含类型的包,即Java类和接口; 其数据包括资源和其他类型的静态信息.

为了控制其代码如何引用其他模块中的类型,模块声明它需要哪些其他模块才能进行编译和运行.为了控制其他模块中的代码如何引用其包中的类型,模块声明它导出哪些包.

模块系统定位所需的模块,与类路径机制不同,它确保模块中的代码只能引用它所依赖的模块中的类型.Java语言和Java虚拟机的访问控制机制阻止代码访问未由其定义模块导出的包中的类型.

除了更可靠之外,模块化还可以提高性能.当模块中的代码引用包中的类型时,该包确保在该模块中或在该模块读取的模块中定义.因此,在寻找特定类型的定义时,不需要在多个模块中搜索它,或者更糟糕的是,在整个类路径中搜索它.

JEPs要遵循

Jigsaw是一个持续了很多年的巨大项目.它有大量的JEP,这是获得更多项目信息的好地方.其中一些JEP如下:

闭幕致辞

模块系统状态报告的初始版本中,Mark Reinhold描述了模块系统的具体目标如下:

  • 可靠的配置,用程序组件的方式替换脆弱的,容易出错的类路径机制,以便相互声明明确的依赖关系,以及
  • 强大的封装,允许组件声明其中哪些公共类型可供其他组件访问,哪些不可访问.

这些功能将直接和间接地使Java SE平台本身的应用程序开发人员,库开发人员和实现者受益,因为他们将实现可扩展的平台,更高的平台完整性和更高的性能.

  • Mark Reinhold是Oracle Java平台组的首席架构师,这个答案基本上是他对这个问题的直接回答. (3认同)

Mic*_*ter 13

为了论证,让我们断言Java 8(及更早版本)已经有模块(jar)和模块系统(类路径)的"形式".但是这些都存在众所周知的问题.

通过检查问题,我们可以说明Jigsaw的动机.(以下假设我们没有使用OSGi,JBoss模块等,它们肯定会提供解决方案.)

问题1:公众过于公开

考虑以下类(假设两者都是公共的):

com.acme.foo.db.api.UserDao
com.acme.foo.db.impl.UserDaoImpl
Run Code Online (Sandbox Code Playgroud)

在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;
}
Run Code Online (Sandbox Code Playgroud)

问题2:反思是肆无忌惮的

鉴于#1中的类,有人仍然可以在Java 8中执行此操作:

Class c = Class.forName("com.acme.foo.db.impl.UserDaoImpl");
Object obj = c.getConstructor().newInstance();
Run Code Online (Sandbox Code Playgroud)

也就是说:反射是强大且必不可少的,但如果不加以控制,它可以用于以不合需要的方式进入模块的内部.马克莱因霍尔德有一个相当惊人的例子.(SO帖子在这里.)

在Jigsaw中,强大的封装提供了拒绝访问类的能力,包括反射.(这可能取决于命令行设置,等待JDK 9的修订技术规范.)请注意,因为Jigsaw用于JDK本身,Oracle声称这将允许Java团队更快地创新平台内部.

问题3:类路径消除了架构关系

团队通常有关于罐子之间关系的心理模型.例如,foo-app.jar可以使用foo-services.jar哪种用途foo-db.jar.我们可能断言,类foo-app.jar不应绕过"服务层"并foo-db.jar直接使用.但是,没有办法通过类路径强制执行.Mark Reinhold 在这里提到了这一点.

相比之下,Jigsaw为模块提供了明确,可靠的可访问性模型.

问题4:单片运行时

Java运行时是单片的rt.jar.在我的机器上,它是60+ MB,20k课程!在微服务,物联网设备等时代,如果不使用Corba,Swing,XML和其他库,则不希望它们存在于磁盘上.

Jigsaw将JDK本身分解为许多模块; 例如,java.sql包含熟悉的SQL类.这有几个好处,但新的jlink工具.假设应用程序完全模块化,则jlink生成可分发的运行时映像,该映像被修剪为仅包含指定的模块(及其依赖项).展望未来,Oracle 设想未来将JDK模块提前编译为本机代码.虽然jlink是可选的,AOT编译是实验性的,但它们是Oracle前进的主要指标.

问题5:版本控制

众所周知,类路径不允许我们使用同一个jar的多个版本:eg bar-lib-1.1.jarbar-lib-2.2.jar.

Jigsaw没有解决这个问题; 马克莱因霍尔德说明了这里理由.要点是Maven,Gradle和其他工具代表了依赖管理的大型生态系统,而另一种解决方案将更有害而不是有益.

应该注意的是,其他解决方案(例如OSGi)确实解决了这个问题(除了#4之外的其他解决方案).

底线

这是Jigsaw的一些关键点,受特定问题的驱动.

请注意,解释Jigsaw,OSGi,JBoss Modules等之间的争议是一个单独的讨论,属于另一个Stack Exchange站点.解决方案之间的差异比此处描述的要多得多.此外,还有足够的共识来批准JSR 376 的公众评论复议投票.