[Java study notes (122)] detailed explanation of the Java platform module system

This article is published by the official account [Developing Pigeon]! Welcome to follow! ! !


Old Rules-Sister Town House:

One. Java platform module system

(I. Overview

       Encapsulation is a feature of object-oriented programming. The declaration of a class consists of a public interface and a private implementation. The class can be evolved in a way that only modifies the implementation without affecting its users. The module system allows classes and packages to be selectively obtained, so that the evolution of modules can be controlled. Many existing Java module systems rely on class loaders to achieve isolation between classes. Java 9 introduces a new system supported by Java compilers and virtual machines, called the Java platform module system.

(2) Module

       A package is a collection of classes. A package provides a package level. All features with package access permissions can only be accessed by methods in the same package. However, in large systems, this level of access control is still insufficient. All public features can be accessed from any location, adding we want to modify or remove a feature that is rarely used, then we have no way of knowing which classes rely on this public feature. The Java platform module system has been successfully used in the modularization of Java API. A Java platform module contains:

  1. A collection of packages
  2. Optionally include resource files and files like native libraries
  3. A list of accessible packages in the module
  4. A list of all other modules that this module depends on

(3) Naming of modules

       A module is a collection of packages. The package names in a module do not need to be related to each other. Just like path names, module names are composed of letters, numbers, underscores and periods, and like path names, there is no hierarchical relationship between modules. . When building a module for others to use, it is important to ensure that its name is globally unique. The easiest way to name a module is to name it according to the top-level package provided by the module, such as the org.slf4j module, which surrounds org.slf4j, org.slf4j.spi, etc. This habit can prevent package name conflicts in the module. Because any given module can only be placed in one module, if the module name is unique and the package name starts with the module name, then the package name must be unique. And the module has no concept of scope, so two packages with the same name cannot be placed in different modules.

       The module name is only used in the module declaration. In the source file of the Java class, only the package name is used.

(4) Modularized program example

1. Create package com.hello

       Create a class HelloWorld under the package


2. Create a module hellomode that contains this package

       You need to add a module declaration to the module, which can be placed in a file named module-info.java, which is located in the base directory (the directory containing the com directory). By convention, the name of the base directory is the same as the name of the module .

module-info.java内容:
module hellomode
{
    
    }

       The module declaration is empty because the module does not have anything that can be provided to other people, nor does it need to rely on anything.

3. Compile the module

       Compile the module declaration with the original class:

javac hellomode/module-info.java hellomode/com/hello/HelloWorld.java

       The module declaration file will finally be compiled in binary form into the class file module-info.class that contains the module definition.

4. Modular running program

       In order for this program to run as a modular application, you need to specify the module path, which is similar to the class path, but contains modules, and you also need to specify the main class in the form of module name/class name:

java --module-path hellomode –module hellomode/com.hello.HelloWorld

(5) Demand for modules

       One of the design goals of the module system is that modules need to clarify their requirements, so that the virtual machine can ensure that all requirements are met before starting the program, that is, which modules the module depends on need to be explicitly written in the module declaration, using the require keyword dependency For other modules, a module cannot directly or indirectly depend on itself, and at the same time, modules will not automatically pass access rights to other modules, that is, dependencies will not be transitive.

module hellomode
{
    
    
	requires java.desktop;
}

(6) Package exported by the module

       A module can use the exports keyword to declare which of its packages can be exported, and other packages are hidden. When the package is exported, its public and protected classes, interfaces and members are also accessible outside the module.

module java.xml
{
    
    
	exports javax.xml;
	exports javax.xml.catelog;}

(7) Module and reflection

       Reflection can access the private members of any class, but in a module, this approach does not work. If a class is in the module, then reflective access to non-public members will fail. Before we used reflection to access private domains, unless the security manager does not allow access to private domains, there are many libraries that use reflection access, such as object-relational mappers such as JPA, which automatically persist objects to the database. . The following is the way to access the private domain:

Field f = obj.getClass().getDeclaredField(“salary”);
f.setAccessible(true);
double value = f.getDouble(obj);
f.setDouble(obj, value * 1.1);

       In the module, use the opens keyword to open the specified package, thereby starting reflective access to all instances of the class in the given package, so that all the content in the package can be accessed, but only visible at runtime The exported package is accessible. As follows:

module hellomode
{
    
    
	opens com.hello
}

(8) Automatic modules and unnamed modules

       If you start from a brand new project, where all the code is written by ourselves, then you can design the module, declare the module dependencies, and package the application into a modular JAR file. But this situation is still unattainable at present, because our project must rely on third-party libraries, and third-party libraries are probably not modularized. Therefore, the Java platform module system provides two mechanisms to solve the current situation: automation modules and Unnamed module.


1. Automation Module

       The JAR of the beauty and module-info.class file on the module path is called an automatic module, and the attributes of the automatic module are:

(1) Implicitly include the requires clauses for all other modules;

(2) All its packages are exported and are open;

(3) If there is an item whose key is Automatic-Module-Name in the META-INF/MANIFEST.MF of the JAR file list, its value will become the module name;

(4) Otherwise, the module name will be obtained from the JAR file name, and the version number at the end of the file name will be deleted


2. Unnamed Module

       Any class that is not in the module path is a part of the unnamed module. Like the automatic module, the unnamed module can access all other modules, and all its packages will be exported and are all open. But no explicit module (non-automatic module, non-unnamed module) can access the unnamed module.

(9) Service loading

       Before the module system, the ServiceLoader class was used to match the service interface with the implementation. In the Java platform module system, this mechanism will be simpler. The service consumer must choose one of all implementations based on the standard that it considers appropriate. In the past, it was provided to the service consumer by placing a text file in the META-INF/services directory containing the JAR file of the implementation class. The module system directly Add the statement to the module descriptor. The module that provides service implementation can add a provides statement, which lists the service interface and implementation class, as shown below:

module jdk.security.auth
{
    
    
	provides javax.security.auth.api.LoginModule with
		com.sun.security.auth.module.UnixLoginModule,}

       This is equivalent to the META-INF/services file, and the consumer module that uses it contains a uses statement:

module java.base
{
    
    
	uses javax.security.auth.spi.LoginModule;
}

       When the code in the consumer module calls ServiceLoader.load(ServiceInterface.class), the matching provider class will be loaded.

Guess you like

Origin blog.csdn.net/Mrwxxxx/article/details/113746925