您的位置 首页 java

JAVA9 模块系统的使用

什么是模块系统

JAVA 9 最大的变化之一是引入了模块系统(Jigsaw 项目)。

模块就是代码和数据的封装体。模块的代码被组织成多个包,每个包中包含Java类和接口;模块的数据则包括资源文件和其他静态信息。

Java 9 模块的重要特征是在其工件(artifact)的根目录中包含了一个描述模块的 module-info.class 文 件。 工件的格式可以是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。这个文件由根目录中的源代码文件 module-info.java 编译而来。该模块声明文件可以描述模块的不同特征。

为什么要使用模块化

java开发者都知道,使用java开发应用程序都会遇到一个问题,Jar hell,他就像windows里的dll hell。

比如我们启动一个不算大的应用,但依赖了很多的jar,如下图:

摘自:Mark Reinhold的演讲 www.youtube.com/watch?v=l1s…

这是很常见的。虽然你可以使用 “java -Djava.ext.dirs=lib xxx” 让命令行小一些,但不可否认,他的classpath就是那么长。顺便说一句,java9中不允许使用extdirs了。

另一方面, jdk 本身有很多的 api

如何使用模块系统

在 module-info.java 文件中,我们可以用新的关键词module来声明一个模块,如下所示。下面给出了一个模块com.mycompany.mymodule的最基本的模块声明。

module com.runoob.mymodule {
}
 

创建模块

接下来我们创建一个 com.runoob.greetings 的模块。

第一步

创建文件夹 /home/xx/JAVA/src,然后在该目录下再创建与模块名相同的文件夹 com.runoob.greetings。

第二步

在 /home/xx/JAVA/src/com.runoob.greetings 目录下创建 module-info.java 文件,代码如下:

module com.runoob.greetings { }
 

module-info.java 用于创建模块。这一步我们创建了 com.runoob.greetings 模块。

第三步

在模块中添加源代码文件,在目录 /home/xx/JAVA/src/com.runoob.greetingscomrunoobgreetings 中创建文件 Java9Tester.java,代码如下:

package com.runoob.greetings;
public class Java9Tester {
 public static void main(String[] args) {
 System.out.println("Hello World!");
 }
}
 

第四步

创建文件夹 /home/xx/JAVA/src/,然后在该目录下创建 com.runoob.greetings 文件夹,编译模块到这个目录下:

 javac -d mods/com.runoob.greetings 
 src/com.runoob.greetings/module-info.java 
 src/com.runoob.greetings/com/runoob/greetings/Java9Tester.java
 

第五步

执行模块,查看输出结果:

C:/>JAVA> java --module-path mods -m com.runoob.greetings/com.runoob.greetings.Java9Tester
Hello World!
 

module-path 指定了模块所在的路径。

-m 指定主要模块。

內建的module

jdk原生的包被归并到內建的module里,如java.base模块:

module java.base{
 exports java.io;
 exports java. lang ;
 exports java.lang. annotation ;
 exports java.lang.invoke;
 exports java.lang.module;
 exports java.lang.ref;
 exports java.lang.reflect;
 exports java.lang.math;
 exports java.lang.net;
 //...
}
 

所有的应用都会默认依赖 java.base,就像以前我们不用显式的 “import java.lang.*;” 一样。

这里验证了前面 HelloWorld 中,为什么反编译模块文件之后会多了一个:”requires java.base;”。

下面的 com.foo.app 模块,不需要显式地引入java.base:

如果此时com.foo.bar 增加了 com.foo.baz 模块的引用。

那么,我们知道 com.foo.bar 也隐式 引入了 java.base。

同样的道理,com.foo.baz 模块也隐式引用了 java.base:

可靠的配置

继续深入下去,我们知道 java.sql 引用了其他大量的api,那么下图就不难理解了。

目前的模块结构,称为可读的模块,提供了可靠的配置。

如果引用了不存在的module,和jar一样,你同样会触发 xx not found.

编译时:

运行时:

可访问的类型

如果引用的模块没有导出某个类,那么是不可访问的,这称为强封装。

比如 com.foo.bar 模块中有一个内部类BetaImpl:

比如 com.foo.bar 模块中有一个内部类BetaImpl:

那么在 com.foo.bar 模块的主动引用模块 com.foo.app 中如下使用 BeatImpl:

在编译时,会触发异常:

就是说:BetaImpl不可访问,因为包 com.foo.bar.beta.internal 包没有被导出。

同样,即便使用导出版本编辑成功,而运行时引用了未导出版本模块:

查看內建的模块

$ jmod list $JAVA_HOME/jmods/java.base.jmod
classes/module-info.class
classes/apple/security/AppleProvider$1.class
...
classes/java/lang/Object.class
...
bin/java
bin/keytool
...
conf/security/java.policy
...
 

查看更多内建模块:

$ java --list-modules
java.activation@9
java.base@9
java.compiler@9
java.corba@9
java.datatransfer@9
java.desktop@9
//...节省篇幅略
 

文章来源:智云一二三科技

文章标题:JAVA9 模块系统的使用

文章地址:https://www.zhihuclub.com/184669.shtml

关于作者: 智云科技

热门文章

网站地图