The Java module is officially implemented in Java 9. I haven’t had time to study it, so today I will learn about it with you.

What problems do Java modules solve

Recently, many students asked me, Fat brother, how to study? What to learn? Here fat brother also interspersed to say. No matter what you learn, you must first find out what it is for you to learn, whether it will be used immediately or useful later. I think when time is limited, it is important to learn what is immediately useful. Let’s take a look at what Java modules really do.

I think the biggest significance of modularization is to separate the code logic according to the function, just like you do the front end, I write the back end, he does the test, the whole concept into small concepts, when using free combination, as needed. It does, but there’s more to it than that.

To simplify the class library

The JDK class library is so bloated that it may not be fully functional on some tiny devices, but in this case it has to reference the entire class library. With the introduction of modules in Java 9, the JDK, JRE, and even JARS can eliminate libraries that are not needed, greatly reducing the size of dependent libraries.

True access isolation

Previously, as long as the class was public, it could be accessed directly in the entire transitive scope of the dependency. However, many times we need to restrict access to some classes in a certain scope and make them somewhat closed. After introducing modules, we can do this, safely hiding some of the internal implementation details that we don’t want exposed.

What is a module?

The modules introduced in Java 9 are a new abstraction layer on top of the Java package. Based on package this is important and needs to be emphasized here.

Module structure

A Java module can consist of one or more Java packages together. The structure can be seen in this diagram:

Create a module

Creating a module requires the following steps:

  • Create a folder, usually a package name, for examplecn.felord.module.
  • Then, incn.felord.moduleSo let’s create onemodule-info.javaFile, this file is calledModule descriptor file.
  • Create a Java package at the same level as the module descriptor file.
  • Finally, write your Java class files in the created package.

Creating a module rule

Creating modules must also follow the following rules:

  • The module name must be unique.

  • The module descriptor file module-info.java must be present.

  • The package name 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 the JDK and JRE. You can list them using Java –list-modules, and here are some of them:

❯.\java.exe --list-modules java.base@17 java.compiler@17 java.datatransfer@17 port java.logging@17 java.management@17 java.management.rmi@17# omit...
Copy the code

Application module

All modules that are created in an application to implement functionality, and routine development that involves modules, should fall into this category.

Automatic module

Existing JAR files feel like they are compatible with older class libraries. They are not 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 jars or classes to the classpath, all of these classes are added to the unnamed module

  • Export only 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.

The statement module

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

module cn.felord {
}
Copy the code

Module names should be more than two words and use an English period. Separated, above is an empty module.

Export package

By default, all packages in a module are private and cannot be accessed by external dependencies, and packages within a module follow the same rules as before. We can use the export keyword to expose specific packages, like this:

module cn.felord {
    exports cn.felord.pkg;
    exports cn.felord.util;
}
Copy the code

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

Concrete Java classes cannot be exported.

Directionally exported package

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

Exports < package name > to < export module 1>,< export module 2>,< export module 3>,...Copy the code

We export the above cn.felord.util direction to com. XXX:

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

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

The scope of the wizard package is module.

Rely on

If a module wants to access packages exported from other modules, it must import the module where the package is to be accessed using the requires keyword. As above, although the cn.felord module opens the cn.felord. PKG package to com.ooo, com.ooo cannot directly use the classes under the package even though com.felord depends on it:

module com.ooo {
    exports com.ooo.pkg;
    // The class under cn.felord.util cannot be used
    requires cn.felord;
}
Copy the code

The scope of requires is the module.

Static dependence

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

module com.xxx {
       // Removing POM dependencies does not compile
    requires static cn.felord;
}
Copy the code

In this example, cn.felord is required at compile time, but optional at run time, somewhat like the

compile
in Maven.

Depend on the transfer

This is looking more and more like Maven! Module A depends on module B, and module B depends on module C. If module A wants to use the packages exposed by module C, the previous rule requires module C. Now you can do this with the help of b, which requires transitive:

module b {
    exports b.pkg;
    // Enable dependency passing
    requires transitive  c; 
}

module c {
   exports c.pkg
}

module a {
   requires b; 
}
Copy the code

All modules that depend on B will automatically depend on the package exported from C. The package exported to has the highest priority.

The use of 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; // Requires static cn. Felord; // Requires static cn. uses com.ooo.pkg.Read; }Copy the code

Uses interfaces or abstract classes that can only be passed in from the module’s own package or requires, requires static, and requires Transitive.

Uses Specifies the required service class or interface.

Give service

We can provide… with … Syntax, which declares the implementation of services in a module for use by other modules (via uses).

Open the reflection

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

Starting with Java 9, it is not opened by default. We can explicitly grant reflection permissions to other modules through Open.

open com.xxx{
}
Copy the code

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

opens

We can also specify the packages that reflection can access using the Labour keyword if we don’t want to open all reflection access:

module com.xxx{
  opens com.xxx.reflect;
}
Copy the code

Opens… to

Of course we can also open specific packages to specific modules to reflect access:

module com.xxx{
  opens com.xxx.reflect to com.ooo;
}
Copy the code

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

conclusion

Modules are mostly about understanding, and practical applications are about slimming systems and relying on JAR level isolation. Build a Multi-module Maven or Gradle project using Java 9 or above.

Follow our public id: Felordcn for more information

Personal blog: https://felord.cn