3

The Java module was officially implemented in Java 9. I haven't had time to study this thing. Today, I will learn this function with you.

What problem does a Java module solve

Recently, many classmates asked me, fat brother, how to study? What to study? The fat brother also interspersed here. No matter what you learn, you must first figure out what you have learned, whether you can use it right away or use it later. I feel that in the case of limited time, it is necessary to learn things that are immediately useful. Next, let's take a look at what Java modules are used for.

I think the biggest meaning of modularization is to divide the code logic according to the function, just like you do the front end, I write the back end, he does the test, and the overall big concept is divided into small concepts, which can be combined freely when used, and quoted as needed. . In fact, it does have a role in this regard, but it is not only so much.

Simplified class library

The JDK class library is currently too bloated, and all functions may not be used on some micro devices, but in the current situation, all the class libraries have to be referenced. Java 9 introducing the module function, JDK, JRE, and even JAR can exclude unused class libraries, greatly reducing the scale of dependent libraries.

true access isolation

Before, as long as the class was public , it could be accessed directly in the entire dependency transitive scope. But many times we need to restrict the access of some classes in a certain range, so that these classes have some closure. After importing the module, we can do this, safely hiding some internal implementation details that we don't want to expose.

What is a module?

The module introduced in Java 9 is a new abstraction layer introduced on the basis of the Java package ( package ). Based on package this is important and needs to be emphasized here.

structure of the module

A Java module can consist of one or more Java packages that are grouped together. The structure can refer to this figure:

Java Modules

Create a module

Creating a module requires the following steps:

  • Create a folder, usually a package name such as cn.felord.module .
  • Then create a cn.felord.module file under module-info.java , this file is called module descriptor file .
  • Create a Java package at the same level as module descriptor file .
  • Finally, write your Java class file under the created package.

Create module rules

Creating modules must also obey the following rules:

  • Module names must be unique.
  • The module descriptor file module-info.java must have.
  • Package names must be unique. We cannot have the same package name even in different modules.
  • Each module will create a jar file. For multiple jars, we need to create separate modules.
  • A project can consist of multiple modules.

module type

Modules also have types, of which there are four.

system module

Modules from JDK and JRE. It can be listed using java --list-modules , part of which is listed here:

❯ .\java.exe --list-modules
java.base@17
java.compiler@17
java.datatransfer@17
java.desktop@17
java.instrument@17
java.logging@17
java.management@17
java.management.rmi@17
# 省略……

application module

All modules that are created in an application to implement functionality, and should fall into this category if modules are involved in day-to-day development.

automatic module

Existing jar files that feel like compatible with old class libraries. They are not actually modules. When we add a non-module jar to the module path, a module with the jar name is created. This module has the following features:

  • All packages are exported by default.
  • All other modules' classes are accessible by default.

unnamed module

Jars and classes added to the classpath. When we add a jar or class to the classpath, all those classes are added to the unnamed module

  • Only export to other unnamed modules and automatic modules. This means that application modules cannot access these classes.
  • It has access to all modules' classes.

module descriptor file

A module has only one module-info.java , and it has format requirements, let's take a look.

declaring module

We just need to do this in module-info.java to declare a module named cn.felord :

module cn.felord {
}

The module name should be more than two words separated by a period . above which is an empty module.

export package

By default, all packages in a module are private and cannot be accessed even by external dependencies. Packages within a module still follow the previous rules and are not affected by the module. We can expose specific packages using the export keyword, like this:

module cn.felord {
    exports cn.felord.pkg;
    exports cn.felord.util;
}

Please note that cn.felord.pkg and exports cn.felord.util cannot be empty packages, exported packages must declare Java objects.

Concrete Java classes cannot be exported.

Directed export package

There is also a directed export, the package is only exposed to a module. It's like a special alcohol or a special cigarette. Its syntax is:

exports <包名> to <目标模块1>,<目标模块2>,<目标模块3>,...

We export the above cn.felord.util orientation to com.xxx :

module cn.felord {
    exports cn.felord.pkg to com.xxx,com.ooo;
    exports cn.felord.util to com.xxx;
}

In the above case, all modules can access cn.felord.pkg , but only com.xxx module can access cn.felord.util .

The scope of the targeting wizard package is module .

rely

If a module wants to access a package exported from another module, the module must import the module containing the package to be accessed using the requires keyword. Just like the above, although the cn.felord module opens the cn.felord.pkg package to com.ooo , even if com.ooo depends on cn.felord , it cannot directly use the classes under the package, you need to do this:

module com.ooo {
    exports com.ooo.pkg;
    // 注释掉 Pkg就变红了 cn.felord.util下面的类无法使用
    requires cn.felord;
}
The scope of requires is module .

static dependencies

Sometimes we only need some modules at compile time and they are optional at runtime. For example, a test or code generation library. This requires static import, the keyword is requires static , for example:

module com.xxx {
       // 移除pom 依赖编译不了
    requires static cn.felord;
}

In this example, cn.felord is required at compile time, but optional at runtime, somewhat like <scope>compile</scope> in Maven .

dependency transit

This looks more and more like Maven! a module depends on b module, and the b module depends on c module. If a module wants to use the package exposed by the c module, the requires module needs to be c according to the previous rules. Now we can do this with the help of requires transitive , because b link, we can do this:

module b {
    exports b.pkg;
    // 开启依赖传递
    requires transitive  c; 
}

module c {
   exports c.pkg
}

module a {
   requires b; 
}
All modules that depend on b will automatically depend on the package exported by c , and the package exported by export to has the highest priority.

use the service

Using the uses keyword, we can specify that our module needs or uses certain services. This service is usually an interface or abstract class. It should not be an implementation class.

module com.xxx {
    requires com.ooo;
    // 移除pom 依赖编译不了
    requires static cn.felord;
    uses com.ooo.pkg.Read;
}

uses can only be passed from the module's own package or the interface or abstract class passed from requires , requires static and requires transitive .

uses is used to specify the required service class or interface.

give service

We can declare the implementation of some services in a module for use by other modules (via uses ) through the provides ... with ... syntax.

open reflection

The Java 9 encapsulation and security of the reflection API has been improved. Using reflection, we can even access the private members of an object.

As of java 9, it is not turned on by default. We can explicitly grant other modules reflection permission via open .

open com.xxx{
}

In this case, all packages of the com.xxx module can be accessed using reflection.

opens

If we don't want to open all reflection access, we can also use the opens keyword to specify the packages that reflection can access:

module com.xxx{
  opens com.xxx.reflect;
}

opens … to

Of course, we can also open specific packages to specified modules for reflective access:

module com.xxx{
  opens com.xxx.reflect to com.ooo;
}

The com.xxx.reflect package of the com.xxx module will be open to the com.ooo module for reflective access.

Summarize

Modules are mainly for understanding, and practical applications are mainly used for system thinning and relying on jar-level isolation. This one builds a multi-module Maven or Gradle project with Java 9 or later, and you can understand it by experimenting with the above.

Follow the public account: Felordcn for more information

Personal blog: https://felord.cn


码农小胖哥
3.8k 声望8k 粉丝