什么是自动模块?

时间:2017-10-14 07:12:03

标签: java java-9 jigsaw java-module

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

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

3 个答案:

答案 0 :(得分:25)

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

什么是自动模块?

模块系统从它在模块路径上找到的每个JAR创建一个模块。对于模块化JAR(即具有模块描述符的JAR),它们定义the module's properties (name, requires, exports)时很简单。对于普通的JAR(没有模块描述符),这种方法不起作用,那么模块系统应该做什么呢?它会自动创建一个模块 - automatic module,可以这么说 - 并对三个属性进行最安全的猜测。

名称

获取名称分为两步:

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

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

需要

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

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

  • 第一个自动模块一解决,所有其他模块也一样。这意味着一旦模块路径上的单个普通JAR被另一个模块引用,所有普通JAR都将作为自动模块加载。
  • 所有其他自动模块上的自动模块imply readability,即读取其中一个模块的模块,读取所有模块。
总而言之,这可能会产生令人遗憾的影响,即依赖于几个普通JAR的显式模块(即非自动模块)只需要其中一个就可以逃脱(只要其他模块路径最终在模块路径上)同样)。

出口/打开

由于JAR不包含哪些包被视为公共API而且不包含任何信息,因此模块系统会导出所有包并打开它们以进行深度反射。

更多

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

最后,还会处理Main-Class清单条目,因此可以像使用jar工具设置主类的自动模块一样启动定义一个的普通JAR(即{ {1}})。

正确的模块

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

什么是的自动模块

引入模块的原因之一是使编译和启动应用程序更加可靠,并且可以更快地发现类路径可能出现的错误。其中一个关键方面是java --module-path my-app.jar --module my.app条款。

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

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

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

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

答案 1 :(得分:2)

  

automatic module 是一个隐式定义的命名模块,   因为它没有模块声明。一个普通的命名模块,   相比之下,使用模块声明明确定义;我们会   从此以后将它们称为显式模块

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

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

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

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

  

..没有实用的方法来分辨哪个包   自动模块旨在供其他模块使用,或者由其他模块使用   类仍然在类路径上。 自动模块中的每个包   因此,即使它实际上是,也被认为是出口的   仅供内部使用。

➜进一步引用链接 -

  

...没有实际的方法可以事先告诉其他哪些模块   自动模块可能依赖于。解决模块图后,   因此,使自动模块读取所有其他命名   模块,无论是自动还是显式。

proposals中的一个 - 自动模块提供传统的封装级别:所有包都是打开以进行深层反射访问导出以进行普通编译 - 时间和运行时访问到他们的公共类型

➜另外,还有一个自动模块

  

向所有其他自动模块授予隐含的可读性

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

  

..无法确定是否可以导出其中一个   自动模块(x.y.z)中的包包含其签名的类型   是指在某些其他自动模块(a.b.c)中定义的类型。

答案 2 :(得分:1)

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

Javadocs在module-info.class包类中提供了大量的正式定义。

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

  

在其顶级目录中没有Automatic-Module-Name的JAR文件定义了自动模块,如下所示:

     
      
  • 如果JAR文件具有属性" java.base"在其主要清单中,它的值是模块名称。否则,模块名称将从JAR文件的名称派生。
  •   
     

...

来自https://docs.oracle.com/javase/9/docs/api/java/lang/module/ModuleDescriptor.html

  

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