什么是Java模块
Java应用程序是由Packages组成的,每个package管理着若干个相关的类。Package会被打包成Jar文件分发给其他应用程序使用。模块是有别于Jar的Package的组织和管理形式,包含代码和数据。模块不是简单的package容器,它通过建立模块之间的依赖关系,可以生成更轻量级的程序。
细心的朋友肯定能发现,自从JDK9以后JDK的文件夹里面不再有诸如rt.jar的Jar文件了。代替它们的是一个叫做jmods的文件夹,里面包存放着包含Java基础类库的Java模块。如下图:
JDK已经将自己的基础jar分割成不同的jmod 模块(此处用“分割”暗指jdk自带jar文件,一个被分成多个jmod文件,jmod相比jar更轻量级)
为什么引进模块
JDK8以及以前遇到的问题
主要包含两方面的问题:
- Jar之间的依赖问题
间接依赖的jar并不包含在直接依赖的jar文件中,如果缺失被间接依赖的jar,在程序运行时就会报classnotfoundexception。
一个程序的依赖同一个jar的不同版本,新版本中并且加入了新的成员。 由于JVM类加载机制的原因,虽然有两个版本的jar,但是同一个类只会被加载一次。当被加载的类是旧版本的,在访问新成员时就会遇到异常。
当然了,关于jar依赖的问题远不止我列出的这些,这些问题统称为Jar Hell. - 包成员的访问控制问题
一个包内的公共(public)成员,在包外可以被任意访问。如果仅限于某些jar可以访问,该怎么办呢?
Java 模块如何解决这些问题
- 针对依赖的问题,java 模块以一个网状的结构来描述模块间的依赖关系。
解决依赖体的具体机制在这里就不详解了。 - 针对访问权限的问题,在Java模块中,只有被exports导出的包才能在模块外访问
Java模块实践
该到举个例子的时候了,现在我们有一个greeting.world.World, 包含于greeting.world模块。
World.java代码如下:
package greeting.world;
public class World {
private String name = "World";
public String getWorld() {
return name;
}
}
module-info.java
module greeting.world {
exports greeting.world;
}
有一个com.greeting.Main 包含在com.greeting模块里,Main类是使用World类。具体代码如下:
Main.java
package com.greeting;
import greeting.world.World;
public class Main {
public static void main(String[] args) {
System.out.println("Greetings " + new World().getWorld());
}
}
module-info.java
module com.greeting{
requires greeting.world;
}
模块com.greeting依赖于greeting.world
编译greeting.world 模块:
首先创建一个mods\greeting.world文件夹
mkdir mods\greeting.world
然后编译模块:
javac -d mods\greeting.world greeting.world\src\module-info.java greeting.world\src\greeting\world\*.java
编译com.greeting 模块:
首先创建一个mods\com.greeting文件夹
mkdir mods\com.greeting
然后编译模块:
javac --module-path mods -d mods\com.greeting greeting\src\module-info.java greeting\src\com\greeting\*.java
此处要增加一个参数–module-path 指定从哪里查找依赖的模块
运行com.greeting.Main
java --module-path mods -m com.greeting/com.greeting.Main
创建模块greeting.world 的Jar文件
mkdir mlib
jar --create --file=mlib/greeting.world@1.0.jar --module-version 1.0 -C mods/greeting.world .
创建模块com.greeting 的Jar文件
jar --create --file=mlib/com.greeting@1.0.jar --module-version 1.0 --main-class com.greeting.Main -C mods/com.greeting .
运行com.greeting模块
java -p mlib -m com.greeting
创建jmod
jmod create --class-path mlib\greeting.world@1.0.jar jmods/greeting.world.jmod
更多例子待续。。。