本篇文章简单的介绍了模块应用的开发,在这个过程中理解模块的概念以及模块的使用。
对于模块化的更强的封装性以及更简单的依赖的特性,当你把理解了模块时什么东西之后自然而然就理解了。
需要声明的是,为了更好的理解模块,本篇不使用任何IDE,直接使用命令行操作,废话不多说,直接开始。
首先第一步就是要安装JDK9了,怎么安装?大家都是老司机了。安装完成后配置环境变量。然后打开命令行,输入下面命令,说明安装成功:
F:\workspace\workspace-for-java9>java -version
java version "9"
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)
java9的安装目录和之前版本有明显区别,有兴趣的可以看一下。重要的就是jmods文件夹,其中包括了很多java自带的模块。
很简单。在工作空间中目录中创建一个文件夹命名为java9test,这样我们的项目工程就建好了。当前的目录结构如下:
-workspace //工作空间
--java9test //项目工程
进入项目工程(java9test)目录中,创建一个名称为moduleone的目录,在这个目录中我们要开发我们的第一个模块。然后进入moduleone目录,创建一个重要的文件,名称为module-info.java。从名称上我们也可以看出来这个文件是记录模块信息的,对于模块来说至关重要。文件内容如下:
module moduleone { //指定了模块的名称是moduleone
}
现在一个空的模块moduleone就完成了,下面我们在模块中添加一些代码。创建一个包,包名为com,com包下包含一个HelloModule.java文件,文件内容如下:
package com;
public class HelloModule{
public static void main(String [] args){
System.out.println("hello module");
}
}
当前目录结构如下:
-workspace //工作空间
--java9test //项目工程
----moduleone
------module-info.java
------com
--------HelloModule.java
打开命令行,进入工程java9test目录中。执行下面命令:
javac -d mods --module-source-path . moduleone/module-info.java moduleone/com/HelloModule.java
没有任何输出就是最好的输出。
说明一下:
执行成功后,java9test目录中会多出一个mods的文件,里面会包含编译后的.class文件。
继续执行如下命令:
java --module-path mods -m moduleone/com.HelloModule
这个命令的意思是执行模块路径mods下的模块moduleone中的HelloModule类。
打印结果输出如下:
hello module
到现在为止,我们的第一个模块就建立完成了。但是到目前为止,什么依赖、封装、更小的JRE我们还都没有看到,我们继续往下看。
和第一个模块类似,在相同的目录下创建moduletwo文件夹,当做第二个模块,在moduletwo中创建module-info.java文件,内容如下:
module moduletwo { //指定了模块的名称是moduletwo
}
然后创建包名log,包下创建类MyLog.java,内容如下:
package log;
public class MyLog{
public void info(String info){
System.out.println("[info]:"+info);
}
}
当前目录结构如下:
-workspace //工作空间
--java9test //项目工程
----moduleone
------module-info.java
------com
--------HelloModule.java
----moduletwo
------log
--------MyLog.java
打开命令行,进入工程java9test目录中。执行下面命令:
javac -d mods --module-source-path . moduletwo/module-info.java moduletwo/log/MyLog.java
在mods中也会出现moduletwo编译后的.class文件。
当前moduleone和moduletwo都在同一个项目工程中。怎么在moduleone中使用moduletwo中的MyLog类呢?按照之前java版本的逻辑就是这样的:MyLog类是public修饰的,并且有默认的构造方法,那也就是说这个类在任何地方都是可访问的,那么在moduleone中直接import log.MyLog;就可以了么吧。答案是否定的,这还不够。
java9中引入了模块,同时也就引入了一个概念,叫做模块可见性。默认模块之间是不可见的,这就是更强的封装性,public不在是任何地方可访问的了,被模块这层墙挡在了外面,这可能颠覆了你对java的认知。可以这么说,更强的封装性就会间接导致更简单的依赖性。
那么怎么让模块之间可见呢?这就需要导出模块和导入模块,具体操作如下:
打开moduletwo中的module-info.java文件,修改如下:
module moduletwo {
exports log; //导出log包
}
exports log;的意思是导出log包,让其他模块可见。
打开moduleone中的module-info.java,修改如下:
module moduleone {
requires moduletwo;//导入模块moduletwo
}
requires moduletwo;表示导入moduletwo模块,moduletwo模块中已经exports log;所以moduleone中就可以看到MyLog类了。
打开HelloModule.java文件,修改如下:
package com;
import log.MyLog;
public class HelloModule{
public static void main(String [] args){
MyLog log = new MyLog();
log.info("hello module");
}
}
重新编译moduleone和moduletwo,命令如下:
javac -d mods --module-source-path . moduletwo/module-info.java moduletwo/log/MyLog.java moduleone/module-info.java moduleone/com/HelloModule.java
命令如下:
java --module-path mods -m moduleone/com.HelloModule
输出结构如下:
[info]:hello module
可以看到,执行成功。到现在为止,你或许已经对模块的强封装和简单依赖有那么一丝丝的了解了。
模块开发完成后,你就需要把模块打成jar包,供其他程序使用。首先我们在java9test中新建一个文件夹,来存放我们的jar包,文件名为mlib。这个文件一定要手动创建,否则会报错的。
然后执行jar命令,如下所示:
jar --create --file mlib/moduleone1.0.jar --module-version 1.0 --main-class com.HelloModule -C mods/moduleone .
注意一定不要忘记命令最后那个点。
jar --create --file mlib/moduletwo1.0.jar --module-version 1.0 -C mods/moduletwo .
注意一定不要忘记命令最后那个点。
命令如下:
java -p mlib -m moduleone
输出结果如下:
[info]:hello module
OK!jar包执行也成功。
之前的java版本中,有一个巨大的jar包,那就是rt.jar。这个jar包在java8中有61M。也就是说不管你的应用有多大,运行时环境最小也得包含这个61M的rt.jar,然后再包含其他的文件就更大了,在本机上我看了一下jre8的大小为170多M。这就限制了java在更小的设备中执行的能力。java9可以实现更小的运行时环境,并提供了一个工具jlink。下面我们就用使用jlink打造一个更小的运行时环境:
在java9test目录下,打开命令行,执行下面命令:
jlink --module-path "mlib;%JAVA_HOME%\jmods" --add-modules moduleone,moduletwo --output deploy --launcher launch=moduleone/com.HelloModule
这个命令会在java9test中生成一个deploy目录,进入deploy目录,会看到一个完整的运行时环境,这个环境只有三十几兆,值得一提的是,我们的两个模块已经存在于这个环境中。进入deploy/bin目录,可以使用下面的命令直接运行项目:
F:\workspace\java9test\deploy\bin>launch.bat
输出结果如下:
[info]:hello module
结束!!!!!!!!