什么是自动模块?

stackoverflow上多次提到自动模块,但我找不到自动模块的完整,简洁和自给自足的定义。

那么,什么是自动模块? 它是否导出所有包裹? 它打开所有包裹吗? 它是否读取所有其他模块?

我首先回答你的实际问题(“什么是自动模块?”),但我也解释了它们的用途 。 很难理解为什么自动模块在没有这些信息的情况下表现得如此。

什么是自动模块?

模块系统从它在模块路径上找到的每个JAR创建一个模块。 对于模块化JAR(即具有模块描述符的JAR),它们可以直接定义模块的属性(名称,要求,导出) 。 对于普通JAR(没有模块描述符),这种方法不起作用,那么模块系统应该做什么呢? 它会自动创建一个模块 – 可以说是一个自动模块 – 并对这三个属性进行最安全的猜测。

名称

获取名称分为两步:

  • 如果JAR在其清单中定义了Automatic-Module-Name标头,则它定义模块的名称
  • 否则,JAR文件名用于确定名称

第二种方法本质上是不稳定的,因此不应发布依赖于这种自动模块的模块。 Maven警告说。

需要

由于普通JAR表示没有require子句,因此模块系统允许自动模块读取所有其他模块,使其成为可读性图 (也就是模块图)。 与显式模块不同,自动模块也会读取未命名的模块,该模块包含从类路径加载的所有内容。 这个看似微不足道的细节变得非常重要(见下文)。

自动模块有一些进一步的可读性怪癖,但是:

  • 第一个自动模块解决后,所有其他模块也一样。 这意味着一旦模块路径上的单个普通JAR被另一个模块引用,所有普通JAR都将作为自动模块加载。
  • 自动模块意味着所有其他自动模块的可读性 ,这意味着读取其中一个模块的模块会读取所有模块。

总而言之,这可能会产生令人遗憾的影响,即依赖于几个普通JAR的显式模块(即非自动模块)只需要其中一个就可以逃脱(只要其他模块路径也在模块路径上) 。

出口/开幕

由于JAR不包含哪些包被视为公共API而哪些包不被认为是公共API,因此模块系统会导出所有包并打开它们以进行深入reflection。

更多

模块系统还扫描META-INF/services并使自动模块提供其中命名的服务。 假设允许自动模块使用所有服务。

最后, Main-Class清单条目也会被处理,因此定义一个的普通JAR可以像自动模块一样启动,其中主类是使用jar工具设置的(即java --module-path my-app.jar --module my.app )。

适当的模块

创建自动模块后,它将被视为任何其他模块。 这明确包括模块系统将其检查为任何其他模块,例如对于拆分包。

什么是自动模块?

引入模块的原因之一是使编译和启动应用程序更可靠,并且可以更快地发现类路径可能出现的错误。 一个关键方面是requires条款。

为了保证它们的可靠性,模块声明无法获得除命名模块之外的任何其他模块,这会排除从类路径加载的所有内容。 如果故事在这里结束,模块化JAR只能依赖于其他模块化JAR,这将迫使生态系统从下往上进行模块化。

然而,这是不可接受的,因此引入自动模块作为模块化JAR依赖于非模块化JAR的手段,您需要做的就是将普通JAR放在模块路径上并通过模块系统的名称来要求它给它。

有趣的是,因为自动模块读取未命名的模块,所以可行(我通常建议这样做)将其依赖项留在类路径上。 这样,自动模块充当从模块到类路径的桥梁。

您的模块可以位于一侧,需要它们作为自动模块的直接依赖关系,并且间接依赖关系可以保留在另一侧。 每当您的一个依赖项变成一个显式模块时,它就会在模块化的一侧离开桥,并将其直接依赖关系作为自动模块绘制到桥上。

自动模块是一个隐式定义的命名模块,因为它没有模块声明 。 相反,一个普通的命名模块是用模块声明明确定义的; 我们今后将把它们称为明确的模块

使用它们的主要好处是,它们允许您在编译或运行时将工件视为模块,而无需等待它迁移到模块化结构。

如果自动模块的主要清单条目中具有属性Automatic-Module-Name ,则自动模块的模块名称派生自用于包含工件的JAR文件。 模块名称是由ModuleFinder从JAR文件的名称ModuleFinder


由于自动模块没有模块声明这一事实,因此告诉所有模块或包读取,打开或导出的内容实际上是不可行的。

➜因此,对于驻留在自动模块中的软件包没有明确的导出/打开,描述为 –

..没有切实可行的方法来判断自动模块中的哪些软件包是供其他模块使用,还是由仍在类路径上的类使用。 因此,即使实际上仅用于内部使用,也认为自动模块中的每个包都被导出。

➜进一步引用链接 –

……没有实际的方法可以提前告诉自动模块可能依赖哪些其他模块。 因此, 解析模块图之后, 使自动模块读取每个其他命名模块,无论是自动还是显式。

其中一个提议 – 自动模块提供传统的封装级别: 所有软件包都可以进行深度reflection访问,导出用于普通编译时和运行时访问其公共类型


➜另外,一个自动模块

授予对所有其他自动模块的可读性

由于这个原因,在一个模块中使用多个自动模块时

..确定自动模块(xyz)中的某个导出包是否包含其签名是指某个其他自动模块(abc)中定义的类型的类型是不可行的。

(你似乎对缺少完整的定义似乎是正确的,因为我没有在语言或JVM规范中找到它)

尽管在java.lang.module包类中,Javadocs提供了大量的正式定义。

来自https://docs.oracle.com/javase/9​​/docs/api/java/lang/module/ModuleFinder.html#automatic-modules的部分引用:

在其顶级目录中没有module-info.class的JAR文件定义了一个自动模块 ,如下所示:

  • 如果JAR文件在其主清单中具有属性“ Automatic-Module-Name ”,则其值为模块名称。 否则,模块名称是从JAR文件的名称派生的。

从https://docs.oracle.com/javase/9​​/docs/api/java/lang/module/ModuleDescriptor.html :

自动模块的模块描述符不声明任何依赖(除了对java.base的强制依赖),并且不声明任何导出或打开的包。 自动模块在分辨率期间接受特殊处理,以便它们读取配置中的所有其他模块。 当在Java虚拟机中实例化自动模块时,它会读取每个未命名的模块,并将其视为导出和打开所有包。