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:
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 undermodule-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 onb
will automatically depend on the package exported byc
, and the package exported byexport 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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。