Java 简明教程

Java - Module System

在 Java 9 中,引入了 Module system 来增强 Java 代码模块性。模块是包上的一种 abstraction 。此 module system 也称为 JPMS, Java Platform Module System 。它通常称为 Modules

In Java 9, Module system was introduced to enhance Java code modularity. Module is an abstraction over package. This module system is also known as JPMS, Java Platform Module System. It is mostly referred as Modules.

What is a Module?

模块是代码和数据的自描述集合,并且有一个名称来对其进行标识。它是一种新型的编程组件,可以包含 packages 、特定于特定功能的配置和资源。模块能够限制对其所包含包的访问。默认情况下,模块中包内的代码对外部世界不可见,即使通过反射也无法访问。从 Java 9 开始,Java 平台本身就被模块化了。如果我们使用 list-modules 命令列出 Java 模块,它将打印 Java 支持的各种模块,如下所示:

A module is a self-describing collection of code and data and has a name to identify it. It a new kind of programming component which can contains packages, configurations, resources specific to a particular functionality. A module is able to restrict access to packages it contains. By default, code in a package within a module is not visible to outside world, not even via reflection. Java platform is itself modularised from java 9 onwards. If we use the list-modules command to list the java modules, it will print the various modules java supports as following:

C:\Users\Mahesh>java --list-modules
java.base@20.0.2
java.compiler@20.0.2
java.datatransfer@20.0.2
java.desktop@20.0.2
java.instrument@20.0.2
java.logging@20.0.2
java.management@20.0.2
java.management.rmi@20.0.2
java.naming@20.0.2
java.net.http@20.0.2
java.prefs@20.0.2
java.rmi@20.0.2
java.scripting@20.0.2
java.se@20.0.2
java.security.jgss@20.0.2
java.security.sasl@20.0.2
java.smartcardio@20.0.2
java.sql@20.0.2
java.sql.rowset@20.0.2
java.transaction.xa@20.0.2
java.xml@20.0.2
java.xml.crypto@20.0.2
jdk.accessibility@20.0.2
jdk.attach@20.0.2
jdk.charsets@20.0.2
jdk.compiler@20.0.2
jdk.crypto.cryptoki@20.0.2
jdk.crypto.ec@20.0.2
jdk.crypto.mscapi@20.0.2
jdk.dynalink@20.0.2
jdk.editpad@20.0.2
jdk.hotspot.agent@20.0.2
jdk.httpserver@20.0.2
jdk.incubator.concurrent@20.0.2
jdk.incubator.vector@20.0.2
jdk.internal.ed@20.0.2
jdk.internal.jvmstat@20.0.2
jdk.internal.le@20.0.2
jdk.internal.opt@20.0.2
jdk.internal.vm.ci@20.0.2
jdk.internal.vm.compiler@20.0.2
jdk.internal.vm.compiler.management@20.0.2
jdk.jartool@20.0.2
jdk.javadoc@20.0.2
jdk.jcmd@20.0.2
jdk.jconsole@20.0.2
jdk.jdeps@20.0.2
jdk.jdi@20.0.2
jdk.jdwp.agent@20.0.2
jdk.jfr@20.0.2
jdk.jlink@20.0.2
jdk.jpackage@20.0.2
jdk.jshell@20.0.2
jdk.jsobject@20.0.2
jdk.jstatd@20.0.2
jdk.localedata@20.0.2
jdk.management@20.0.2
jdk.management.agent@20.0.2
jdk.management.jfr@20.0.2
jdk.naming.dns@20.0.2
jdk.naming.rmi@20.0.2
jdk.net@20.0.2
jdk.nio.mapmode@20.0.2
jdk.random@20.0.2
jdk.sctp@20.0.2
jdk.security.auth@20.0.2
jdk.security.jgss@20.0.2
jdk.unsupported@20.0.2
jdk.unsupported.desktop@20.0.2
jdk.xml.dom@20.0.2
jdk.zipfs@20.0.2

C:\Users\Mahesh>

在这里我们可以看到,jdk 特定包在 jdk 模块中,而库特定包在 java 模块中。

Here we can see, that jdk specific packages are in jdk module and library specific packages are in java module.

Features of Java Module System

有了模块组件,以下增强已添加到 Java 9 中 −

With the Modules component, following enhancements has been added in Java 9 −

  1. A new optional phase, link time is introduced. This phase is in-between compile time and run time. During this phase, a set of modules can be assembled and optimized, making a custom runtime image using jlink tool.

  2. javac, jlink, and java have additional options to specify module paths, which further locate definitions of modules.

  3. JAR format updated as modular JAR, which contains module-info.class file in its root directory.

  4. JMOD format introduced, a packaging format (similar to JAR) which can include native code and configuration files.

Declaring Module

为了声明模块,我们需要在应用程序的根文件夹中创建一个 module-info.java。此文件包含所有元数据或模块描述。

In order to declare a module, we need to create a module-info.java in root folder of the application. This file contains all the meta data or module descriptions.

Example

module-info.java

module com.tutorialspoint.greetings {

}

Adding Dependent Modules

我们可以在模块中声明其他模块的依赖项。例如,如果我们想要使用 com.tutorialspoint.util 模块,则可以如下添加声明:

We can declare dependencies of other modules in the module. For example, if we want to use com.tutorialspoint.util module then we can add the declaration as follows:

Example

module com.tutorialspoint.greetings {
   requires com.tutorialspoint.util;
}

Adding Optional Modules

我们可以使用模块中的 static 关键字来声明其他模块的可选依赖项。例如,如果我们想要使用 com.tutorialspoint.logging 模块,则可以如下添加声明:

We can declare optional dependencies of other modules using static keyword in the module. For example, if we want to use com.tutorialspoint.logging module then we can add the declaration as follows:

Example

module com.tutorialspoint.greetings {
   requires com.tutorialspoint.util;
   requires static com.tutorialspoint.logging;
}

Adding Transitive Modules

我们可以使用模块中的 transitive 关键字来声明其他模块的传递依赖项。例如,如果我们想要使用 com.tutorialspoint.base 模块作为 com.tutorialspoint.util 模块的依赖项,则可以如下添加声明:

We can declare transitive dependencies of other modules using transitive keyword in the module. For example, if we want to use com.tutorialspoint.base module as dependency of com.tutorialspoint.util module then we can add the declaration as follows:

Example

module com.tutorialspoint.greetings {
   requires com.tutorialspoint.util;
   requires static com.tutorialspoint.logging;
   requires transitive com.tutorialspoint.base;
}

这意味着,如果一个模块想要使用 com.tutorialspoint.greetings,那么该模块也需要在模块声明中添加 com.tutorialspoint.base 模块。

This means if a module wants to use com.tutorialspoint.greetings then that module is required to add com.tutorialspoint.base module as well in module declaration.

Export Public Classes

默认情况下,模块的包中没有公共类会公开给外界。为了使用公共类,我们必须按如下所示对其进行导出:

By default, no public class of a package of a module is exposed to outside world. In order to use the public class, we’ve to export it as shown below:

Example

module com.tutorialspoint.greetings {
   requires com.tutorialspoint.util;
   requires static com.tutorialspoint.logging;
   requires transitive com.tutorialspoint.base;

   exports com.tutorialspoint.greetings.HelloWorld;
}

Allow Reflection

默认情况下,不能通过反射来访问模块的包中的任何私有成员。为了允许反射检查类或模块,我们必须按如下所示使用 opens 命令:

By default, no private member of a package of a module is accessible via reflection. In order to allow reflection to inspect the class or module, we’ve to use opens command as shown below:

Example

module com.tutorialspoint.greetings {
   requires com.tutorialspoint.util;
   requires static com.tutorialspoint.logging;
   requires transitive com.tutorialspoint.base;

   exports com.tutorialspoint.greetings.HelloWorld;
   opens com.tutorialspoint.greetings.HelloWorld;
}

如果我们需要允许整个模块对反射开放,我们可以按如下所示使用 open 命令:

If we need to allow complete module to be open for reflection, we can use open command as shown below:

open module com.tutorialspoint.greetings {
   requires com.tutorialspoint.util;
   requires static com.tutorialspoint.logging;
   requires transitive com.tutorialspoint.base;

   exports com.tutorialspoint.greetings.HelloWorld;
}

Creating and Using Java Module

遵循这些步骤来创建一个名为 com.tutorialspoint.greetings 的模块。

Following the steps to create a module say com.tutorialspoint.greetings.

Step 1

创建一个文件夹 C:\>JAVA\src。现在创建一个文件夹 com.tutorialspoint.greetings,该文件夹与我们创建的模块同名。

Create a folder C:\>JAVA\src. Now create a folder com.tutorialspoint.greetings which is same as the name of module we’re creating.

Step 2

在 C:\>JAVA\src\com.tutorialspoint.greetings 文件夹中使用以下代码创建 module-info.java。

Create module-info.java in C:\>JAVA\src\com.tutorialspoint.greetings folder with following code.

module-info.java

module com.tutorialspoint.greetings { }

module-info.java 是用于创建模块的文件。在此步骤中,我们创建了名为 com.tutorialspoint.greetings 的模块。根据惯例,此文件应该驻留在名称与模块名称相同的文件夹中。

module-info.java is the file which is used to create module. In this step we’ve created a module named com.tutorialspoint.greetings. By convention this file should reside in the folder whose name is same as module name.

Step 3

在模块中添加源代码。在 C:\>JAVA\src\com.tutorialspoint.greetings\com\ tutorialspoint\greetings 文件夹中使用以下代码创建 Java9Tester.java。

Add the source code in the module. Create Java9Tester.java in C:\>JAVA\src\com.tutorialspoint.greetings\com\ tutorialspoint\greetings folder with following code.

Java9Tester.java

package com.tutorialspoint.greetings;

public class Java9Tester {
   public static void main(String[] args) {
      System.out.println("Hello World!");
   }
}

根据惯例,要位于该模块名称的同一目录中。

By convention, the source code of a module to lie in same directory which is the name of the module.

Step 4

创建文件夹 C:\>JAVA\mods。现在创建名称与我们创建的模块相同的文件夹 com.tutorialspoint.greetings。现在将模块编译到 mods 目录。

Create a folder C:\>JAVA\mods. Now create a folder com.tutorialspoint.greetings which is same as the name of module we’ve created. Now compile the module to mods directory.

C:/ > JAVA > javac -d mods/com.tutorialspoint.greetings
   src/com.tutorialspoint.greetings/module-info.java
   src/com.tutorialspoint.greetings/com/tutorialspoint/greetings/Java9Tester.java

Step 5

让我们运行模块以查看结果。运行以下命令。

Let’s run the module to see the result. Run the following command.

C:/>JAVA>java --module-path mods -m com.tutorialspoint.greetings/com.tutorialspoint.greetings.Java9Tester

此处 module-path 提供了模块位置为 mods,而 -m 表示主模块。

Here module-path provides the module location as mods and -m signifies the main module.

它将在控制台上打印以下输出。

It will print the following output on console.

Hello World!