JDK9模块化知识和规则入门

  • JEP 282: Jlink: The Java Linker

  • JSR 376: Java Platform module System

  • JSR 379: Java SE 9

现在让我们比较一下Java8和Java9应用程序。

比较Java8和Java9应用程序

=====================

您已经使用版本5、6、7和8开发了许多Java应用程序,因此您可能非常了解9之前的Java应用程序的外观及其包含的组件。对于那些需要复习的人,Java SE 8应用程序:

JDK9模块化知识和规则入门_第1张图片

以及Java9应用程序:

JDK9模块化知识和规则入门_第2张图片

在Java8和更早的应用程序中,顶级组件是包 package 。它将一组相关类型放入一个组中。它还包含一组资源。

java9应用程序与java8没有太大区别;它引入了一个新组件 module ,用于将一组相关的包放入一个组中。同时还介绍了另一个新组件:模块描述符module-info.java

Java8应用程序将包作为顶级组件,Java9应用程序将模块作为顶级组件。

=========================================

顺便说一下,每个Java9模块只能是一个具有一个模块描述符的模块。与Java8包不同,您不能将多个模块构建到单个模块中。

下面列出了Java 9模块中的主要组件:

  • 一个模块

  • 模块名称

  • 模块描述符

  • 成套设备

  • 类型和资源集

资源可以是模块描述符或任何其他属性或XML。

接下来,让我们深入研究模块和模块描述符。

模块和模块描述符基础

==============

现在我们将讨论模块和模块描述符基础的两个更重要的概念:语法和规则。

模块基础知识和规则

=============

在开发任何Java 9模块时,应记住以下重要的基本规则:

  • 每个模块都有一个唯一的名称

  • 每个模块在源文件中都有一些描述

  • 模块描述符文件放在顶层目录中

  • 每个模块可以有任意数量的包和类型

  • 一个模块可以依赖于任意数量的模块

每个模块都有一个唯一的名称

=================

因为模块位于JVM的全局空间中,所以每个模块都应该有一个唯一的名称。与包和JAR文件名一样,可以使用反向域名模式来定义模块名。

例如,如果您要为http://www.taman.com.eg域名开发模块,则可以使用例如: eg.com.taman.mod1 作为第一个模块名,例如: eg.com.taman.mod2 作为第二个模块名,依此类推。

每个模块在源文件中都有一些描述

===================

模块描述在名为Module的源文件中表示module-info.java应该这样命名。每个模块应该只有一个模块描述符(module-info.java).

模块描述符是一个Java文件。它不是XML、文本或属性文件。

模块描述符文件放在顶层目录中

==================

顶层目录是模块的根文件夹。

例如,如果您要开发例如: eg.com.taman.mod1 模块,则应将模块描述符放在例如: eg.com.taman.mod1 模块目录。

每个模块可以有任意数量的包和类型

====================

一个模块可以依赖于任意数量的模块。

JDK9模块化知识和规则入门_第3张图片

现在,让我们看看模块描述符中有什么。

模块描述符

=========

在Java9模块中,模块描述符是包含描述模块的模块元数据的资源。它不是XML或属性文件,而是普通的Java文件。

必须将此文件命名为module-info.java并将其放在模块的根文件夹中。与其他Java源文件一样,模块文件被编译到模块中module-info类使用 javac 命令。

使用module关键字创建模块描述符:

module {

// Module Meta Data goes here.

}

例如:

module eg.com.taman.mod1 {

}

这是一个简单而最小的模块描述符示例。让我们讨论一下模块元数据。

模块元数据

模块包含以下基本元数据:

  • 唯一的名字

  • 出口条款

  • requires子句

我将在下面的部分更深入地讨论并提供一些示例。

唯一的名字

=========

模块具有唯一的名称。使用module关键字定义模块类型,如本例所示:

module eg.com.taman.mod1 {

}

出口条款

========

模块可以将其包导出到外部世界,以便其他模块可以使用它们。在模块描述符中,使用 exports 子句将包导出到外部世界或其他模块:

module eg.com.taman.mod1 {

exports eg.com.taman.service;

}

请注意,并非强制导出所有包。由你决定导出哪一种。

requires子句

==============

模块可以导入或使用其他模块包。在模块描述符中,使用requires子句导入其他模块以使用其包:

module eg.com.taman.mod2 {

requires eg.com.taman.mod1;

}

正如你在这个例子中看到的, eg.com.taman.mod1 已导出 eg.com.taman.service ,所以 eg.com.taman.mod2 要求mod1导入其导出的所有包,以便在其子类型(类、枚举、接口等)中使用它们。

但是请记住, exports 关键字将包导出到其他模块,并且需要关键字 imports 模块才能在内部使用所有导出的包。在模块中定义但未导出的任何包都是私有封装的,永远无法访问。

一个模块可以有超过这个数量的元数据,但这足以让您开始模块化编程。

现在,让我们确定一些关于模块描述符语法的要点。

关于模块描述符的注意事项

================

在构建模块描述符之前,您应该记住以下要点:

  • 模块描述符可以只包含模块名而不包含其他内容;不包含导出或requires子句。

  • 模块描述符可以由一个或多个exports子句组成,而不包含requires子句;这意味着它将包导出到其他模块,但不依赖于任何其他模块—它是一个独立的模块。

  • 模块描述符可以同时具有exports和requires子句;这意味着它将包导出到其他模块并使用其他模块的包—因为它依赖于其他模块,所以它不是一个独立的模块。

  • 模块描述符可以有零个、一个或多个requires子句。

模块是从modulepath加载的(就像类是从类路径加载的一样)。

等等,你说。为什么我不能像以前那样使用类路径?

为什么选择modulepath?

====================

作为一名Java开发人员,您知道什么是类路径地狱:与Windows®编程中的DLL地狱类似,Java中的类路径地狱之所以出现,是因为您的程序不是一组固定的代码,而是JVM在特定实例中加载的一组类。您的代码可能处于这样一种情况:由于解析规则,平台上的同一命令行会导致不同的行为。目录结构可能不同。标准库的版本可以不同,也可以隐藏。因为Java支持第一次遇到的策略,所以未知的排序依赖关系可能会使代码变得混乱。

从Java9开始,您将跳入另一种地狱: modulepath地狱

类路径是用户定义并内置的一系列类和包或jar。JVM或Java编译器需要类路径来编译应用程序或类。

在Java9之前,编译器和运行时通过类路径定位类型:包含已编译Java类的文件夹和库存档文件的列表。它是由CLASSPATH环境变量、放在JRE特殊文件夹中的扩展以及提供给javac和java命令的选项的组合定义的。目标是减少应用程序启动时间。

因为类型可以从几个不同的位置加载,所以搜索这些位置的顺序会导致应用程序变得脆弱。

很多年前,我在我的系统上安装了一个来自第三方供应商的Java应用程序。该应用程序的安装程序将一个旧版本的Java库放入JRE的extensions文件夹中。我系统上的几个Java应 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 用程序依赖于该库的更新版本,因为它包含了库的旧类型的附加类型和增强版本。

因为JRE的extensions文件夹中的类是在类路径上的其他类之前加载的,所以依赖于较新库版本的应用程序停止工作,在运行时出现 NoClassDefFoundErrors 和 NoSuchMethodErrors 失败,有时是在应用程序开始执行很久之后。

modulepath是一系列模块(以文件夹或JAR格式提供)。如果模块是文件夹格式,则表示该模块是分解模块格式。如果它是JAR格式的,那么这个JAR就是模块化JAR。

模块和模块描述符提供的可靠配置有助于消除许多此类运行时类路径问题。每个模块都显式地声明其依赖项,这些依赖项作为应用程序启动来解析。

你可能感兴趣的:(Java,经验分享,架构,java)