Understanding Java 9 Modules<译>

December 13, 2022 作者: yijianhao 分类: jdk文档翻译 浏览: 219 评论: 0

In this article, I introduce the Java 9 Platform Module System (JPMS), the most important new software engineering technology in Java since its inception. Modularity—the result of Project Jigsaw—helps developers at all levels be more productive as they build, maintain, and evolve software systems, especially large systems.

在这篇文章中,我介绍了Java 9平台模块系统(JPMS),自从JAVA面世以来最重要的新软件工程技术。模块化——Jigsaw项目的结晶,帮助各级开发人员在构建、维护以及发展软件系统,尤其是大型系统中,拥有更高的生产效率。

What Is a Module?

Modularity adds a higher level of aggregation above packages. The key new language element is the module—a uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor specifying

模块化在包之上增加了更高级的聚合度。新语言元素的关键是模块——一个唯一命名,可重用的相关包组,以及资源(例如图片和XML文件)和模块描述符号,指定为

  • the module’s name 模块名
  • the module’s dependencies (that is, other modules this module depends on) 模块的依赖(也就是说,这个模块所依赖的其他模块)
  • the packages it explicitly makes available to other modules (all other packages in the module are implicitly unavailable to other modules) 它显示地提供给其他模块的包(模块中隐式的包对其他模块不可见)
  • the services it offers 它提供的服务
  • the services it consumes 它消费的服务
  • to what other modules it allows reflection 到其他允许反射的模块

History

The Java SE platform has been around since 1995. There are now approximately 10 million developers using it to build everything from small apps for resource-constrained devices—like those in the Internet of Things (IoT) and other embedded devices—to large-scale business-critical and mission-critical systems. There are massive amounts of legacy code out there, but until now, the Java platform has primarily been a monolithic one-size-fits-all solution. Over the years, there have been various efforts geared to modularizing Java, but none is widely used—and none could be used to modularize the Java platform.

Java SE 平台自1995年开始就一直存在着,现今大约有10亿开发者使用它去开发任何东西,从资源受限的小型app(比如物联网IOT和其他嵌入式设备)到大规模业务关键型和任务关键型系统。那里有大量的遗留代码,但直到现在,Java平台主要是一个整体式的通用解决方案。多年来,已经在模块化Java的方向上作出了许多努力,但没有一个被广泛使用的方案,而且没有一个可以用来模块化JAVA的平台。

Modularizing the Java SE platform has been challenging to implement, and the effort has taken many years. JSR 277: Java Module System was originally proposed in 2005 for Java 7. This JSR was later superseded by JSR 376: Java Platform Module System and targeted for Java 8. The Java SE platform is now modularized in Java 9, but only after Java 9 was delayed until September 2017.

模块化JAVA SE平台一直都很具有挑战性,这项工作已经花费了数年。JSR 277: Java模块系统最初是在2005年为Java 7提出的。JSR 277后来被JSR 376取代:针对Java 8的Java平台模块系统。现在Java SE平台在Java 9中模块化了,但这是在Java 9被推迟到2017年9月之后。

Goals

According to JSR 376, the key goals of modularizing the Java SE platform are

根据JSR 376,模块化Java Se的关键目标是:

  • Reliable configuration—Modularity provides mechanisms for explicitly declaring dependencies between modules in a manner that’s recognized both at compile time and execution time. The system can walk through these dependencies to determine the subset of all modules required to support your app.
    可靠的配置——模块化提供了一种机制,可以在编译时和运行时显式地声明模块之间的依赖关系。系统可以遍历这些依赖关系,以确定支持你的程序所需的所有模块的子集。
  • Strong encapsulation—The packages in a module are accessible to other modules only if the module explicitly exports them. Even then, another module cannot use those packages unless it explicitly states that it requires the other module’s capabilities. This improves platform security because fewer classes are accessible to potential attackers. You may find that considering modularity helps you come up with cleaner, more logical designs.
    强封装:一个模块中的包只有在该模块显式导出时,其他模块才能访问它们。即使这样,其他模块也不能使用这些包,除非它明确声明它需要其他模块的功能。这提高了平台的安全性,因为潜在的攻击者可以访问的类更少。你可能会发现,考虑模块化可以帮助你做出更简洁、更符合逻辑的设计。
  • Scalable Java platform—Previously, the Java platform was a monolith consisting of a massive number of packages, making it challenging to develop, maintain and evolve. It couldn’t be easily subsetted. The platform is now modularized into 95 modules (this number might change as Java evolves). You can create custom runtimes consisting of only modules you need for your apps or the devices you’re targeting. For example, if a device does not support GUIs, you could create a runtime that does not include the GUI modules, significantly reducing the runtime’s size.
    可扩展的Java平台:在此之前,Java平台是一个由大量包组成的庞然大物,这给开发、维护和演进带来了挑战。它不容易被子集化。这个平台现在模块化为95个模块(这个数字可能会随着Java的发展而变化)。你可以为你的应用程序或目标设备创建自定义运行时,只包含你需要的模块。例如,如果设备不支持GUI,您可以创建一个不包含GUI模块的运行时,从而显著减少运行时的大小。
  • Greater platform integrity—Before Java 9, it was possible to use many classes in the platform that were not meant for use by an app’s classes. With strong encapsulation, these internal APIs are truly encapsulated and hidden from apps using the platform. This can make migrating legacy code to modularized Java 9 problematic if your code depends on internal APIs.
    更好的平台完整性:在Java 9之前,平台中可以使用很多应用程序不能使用的类。通过强大的封装,这些内部api被真正封装并对使用该平台的应用程序隐藏。如果代码依赖于内部api,那么将遗留代码迁移到模块化的Java 9会有问题。
  • Improved performance—The JVM uses various optimization techniques to improve application performance. JSR 376 indicates that these techniques are more effective when it’s known in advance that required types are located only in specific modules.
    性能提升:JVM使用各种优化技术来提高应用程序的性能。JSR 376指出,如果事先知道所需的类型只位于特定的模块中,那么这些技术将更加有效。

Listing the JDK’s Modules

A crucial aspect of Java 9 is dividing the JDK into modules to support various configurations. (Consult “JEP 200: The Modular JDK.” All the Java modularity JEPs and JSRs are shown in Table 1.) Using the java command from the JDK’s bin folder with the --list-modules option, as in:

Java 9的一个重要方面是将JDK划分为支持各种配置的模块。(请参阅“JEP 200: The Modular JDK.”。所有Java模块化jep和jsr如表1所示。)使用java命令,在JDK的bin文件夹中添加--list-modules参数,如下所示:

java --list-modules

lists the JDK’s set of modules, which includes the standard modules that implement the Java Language SE Specification (names starting with java), JavaFX modules (names starting with javafx), JDK-specific modules (names starting with jdk) and Oracle-specific modules (names starting with oracle). Each module name is followed by a version string—@9 indicates that the module belongs to Java 9.

列出JDK的模块集,其中包括实现Java Language SE规范的标准模块(以Java开头的名称)、JavaFX模块(以JavaFX开头的名称)、JDK专用模块(以JDK开头的名称)和oracle专用模块(以oracle开头的名称)。每个模块名称后面都跟着一个版本字符串——@9表示该模块属于Java 9。

Module Declarations

As we mentioned, a module must provide a module descriptor—metadata that specifies the module’s dependencies, the packages the module makes available to other modules, and more. A module descriptor is the compiled version of a module declaration that’s defined in a file named module-info.java. Each module declaration begins with the keyword module, followed by a unique module name and a module body enclosed in braces, as in:

前面提到过,一个模块必须提供一个模块描述符——用来指定该模块的依赖项、该模块可以被其他模块使用的包,等等的元数据。模块描述符是模块声明编译后的版本,定义在文件module-info.java中。每个模块声明都以关键字module开头,后面跟着一个唯一的模块名称和用大括号括起来的模块主体,如下所示:

module modulename { 
}

The module declaration’s body can be empty or may contain various module directives, including requires, exports, provides…with, uses and opens (each of which we discuss). As you’ll see later, compiling the module declaration creates the module descriptor, which is stored in a file named module-info.class in the module’s root folder. Here we briefly introduce each module directive. After that, we’ll present actual module declarations.

模块声明的主体可以是空的,也可以包含各种模块指令,包括requireexportsprovided…withusesopened(我们将逐一讨论)。稍后你会看到,编译模块声明会创建模块描述符,该描述符存储在模块根目录下名为module-info.class的文件中。这里我们简要介绍每个模块指令。之后,我们将展示实际的模块声明。

The keywords exports, module, open, opens, provides, requires, uses, with, as well as to and transitive, which we introduce later, are restricted keywords. They’re keywords only in module declarations and may be used as identifiers anywhere else in your code.

后面将介绍的关键字exportsmoduleopenopensprovidedsrequiresuseswith以及totransitive都是受限关键字。它们只是模块声明中的关键字,也可以作为标识符在代码的其他地方使用。

requires. A requires module directive specifies that this module depends on another module—this relationship is called a module dependency. Each module must explicitly state its dependencies. When module A requires module B, module A is said to read module B and module B is read by module A. To specify a dependency on another module, use requires, as in:
requires modulename;
requires. A require module指令指出这个模块依赖于另一个模块,这种关系称为模块依赖。每个模块都必须显式声明其依赖关系。当模块A需要模块B时,模块A读取模块B,模块A读取模块B。要指定对另一个模块的依赖,可以使用requires,如下所示:
requires modulename;

There is also a requires static directive to indicate that a module is required at compile time, but is optional at runtime. This is known as an optional dependency and won’t be discussed in this introduction.

还有一个require static指令,指示一个模块在编译时是必需的,但在运行时是可选的。这被称为可选依赖项,在本介绍中不会讨论。

requires transitive—implied readability. To specify a dependency on another module and to ensure that other modules reading your module also read that dependency—known as implied readability—use requires transitive, as in:
requires transitive modulename;

requires transitive:隐式可读性。要指定对另一个模块的依赖,并确保读取你的模块的其他模块也会读取该依赖,这被称为隐含可读性,使用需要传递性,如下所示:
requires transitive modulename;

Consider the following directive from the java.desktop module declaration:

思考下面来自java.desktop模块声明的指令:

requires transitive java.xml;

In this case, any module that reads java.desktop also implicitly reads java.xml. For example, if a method from the java.desktop module returns a type from the java.xml module, code in modules that read java.desktop becomes dependent on java.xml. Without the requires transitive directive in java.desktop’s module declaration, such dependent modules will not compile unless they explicitly read java.xml.

在这个例子中,任何读取java.desktop的模块都会隐式地读取java.xml。例如,如果java.desktop模块中的方法返回java.xml模块中的类型,模块中读取java.desktop的代码就会依赖java.xml。如果在java.desktop的模块声明中没有require传递指令,这些依赖的模块将无法编译,除非显式地读取java.xml。

According to JSR 379 Java SE’s standard modules must grant implied readability in all cases like the one described here. Also, though a Java SE standard module may depend on non-standard modules, it must not grant implied readability to them. This ensures that code depending only on Java SE standard modules is portable across Java SE implementations.

根据JSR 379, Java SE的标准模块必须在这里描述的所有情况下授予隐式可读性。另外,尽管Java SE标准模块可能依赖于非标准模块,但不能赋予它们隐式可读性。这确保了只依赖于Java SE标准模块的代码可以在Java SE实现之间移植。

exports and exports…to. An exports module directive specifies one of the module’s packages whose public types (and their nested public and protected types) should be accessible to code in all other modules. An exports…to directive enables you to specify in a comma-separated list precisely which module’s or modules’ code can access the exported package—this is known as a qualified export.

exports and exports…to: exports模块指令指定了模块的一个包,该包的公共类型(以及它们嵌套的公共类型和受保护类型)应该可以被所有其他模块中的代码访问。exports…to指令允许您在逗号分隔的列表中精确指定哪些模块的代码可以访问导出的包——这被称为合格导出。

uses. A uses module directive specifies a service used by this module—making the module a service consumer. A service is an object of a class that implements the interface or extends the abstract class specified in the uses directive.

uses. A uses module指令指定此模块使用的服务——使该模块成为服务使用者。服务是类的对象,它实现了uses指令中指定的接口或扩展了抽象类。

provides…with. A provides…with module directive specifies that a module provides a service implementation—making the module a service provider. The provides part of the directive specifies an interface or abstract class listed in a module’s uses directive and the with part of the directive specifies the name of the service provider class that implements the interface or extends the abstract class.

provides…with. A: provides…with module指令指定模块提供服务实现——使模块成为服务提供者。该指令的providers部分指定了模块的uses指令中列出的接口或抽象类,而with部分指定了实现该接口或扩展抽象类的服务提供者类的名称。

open, opens, and opens…to. Before Java 9, reflection could be used to learn about all types in a package and all members of a type—even its private members—whether you wanted to allow this capability or not. Thus, nothing was truly encapsulated.

open, opens, and opens…to:在Java 9之前,可以使用反射来了解包中的所有类型和类型的所有成员(甚至是它的私有成员),无论您是否希望允许这种功能。因此,没有什么是真正的封装。

A key motivation of the module system is strong encapsulation. By default, a type in a module is not accessible to other modules unless it’s a public type and you export its package. You expose only the packages you want to expose. With Java 9, this also applies to reflection.

模块系统的一个关键动机是强大的封装性。默认情况下,一个模块中的类型不能被其他模块访问,除非它是公共类型,并且你导出了它的包。只公开想要公开的包。在Java 9中,反射也是如此。

Allowing runtime-only access to a package. An opens module directive of the form
opens package

Allowing runtime-only access to a package:一个opens module指令,写法为:
opens package

indicates that a specific package’s public types (and their nested public and protected types) are accessible to code in other modules at runtime only. Also, all the types in the specified package (and all of the types’ members) are accessible via reflection.

表示特定包的公共类型(及其嵌套的公共和保护类型)只能在运行时被其他模块中的代码访问。此外,指定包中的所有类型(以及所有类型的成员)都可以通过反射访问。

Allowing runtime-only access to a package by specific modules. An opens…to module directive of the form
opens package to comma-separated-list-of-modules

Allowing runtime-only access to a package by specific modules:opens…to module 指令的写法为:
opens package to comma-separated-list-of-modules

indicates that a specific package’s public types (and their nested public and protected types) are accessible to code in the listed modules at runtime only. All of the types in the specified package (and all of the types’ members) are accessible via reflection to code in the specified modules.

表示特定包的公共类型(及其嵌套的公共和保护类型)只能在运行时被列出的模块中的代码访问。指定包中的所有类型(以及所有类型的成员)都可以通过反射到指定模块中的代码来访问。

Allowing runtime-only access to all packages in a module. If all the packages in a given module should be accessible at runtime and via reflection to all other modules, you may open the entire module, as in:

Allowing runtime-only access to all packages in a module:如果给定模块中的所有包都应该在运行时可以访问,并且可以通过反射访问所有其他模块,那么你可以打开整个模块,如下所示:

open module modulename {
   // module directives
} 

Reflection Defaults

By default, a module with runtime reflective access to a package can see the package’s public types (and their nested public and protected types). However, the code in other modules can access all types in the exposed package and all members within those types, including private members via setAccessible, as in earlier Java versions.

默认情况下,对包具有运行时反射访问的模块可以看到包的公共类型(以及它们嵌套的公共类型和受保护类型)。但是,其他模块中的代码可以访问公开包中的所有类型以及这些类型中的所有成员,包括通过setAccessible访问的私有成员,就像在早期Java版本中一样。

For more information on setAccessible and reflection, see Oracle’s documentation.

更多关于setAccessiblereflection反射的信息,请看文档


评论