首页 >> 大全

Java9新特性——module模块系统

2024-01-04 大全 29 作者:考证青年

官方文档:

关于 java9的新特性,官方原文:

这玩意就是一个列表,具体的技术细节需要根据官方文档挖一挖。

-模块系统

java9的模块化,从一个独立的开源项目而来,名为。

项目官网:

为什么要使用模块化

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

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

输入图片说明

摘自:Mark 的演讲

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

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

输入图片说明

对于一些小设备,它太庞大了。

还是习惯先来一个。在此之前,需要先检查一下你的java版本:

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,而是 1.8、1.7,那么慢走不送。

创建主类

首先创建一个java类,就叫Demo吧。

文件保存为:src/com///Demo.java

package com.pollyduan.modular;public class Demo{public static void main(String[] args){System.out.println("hello modular.");}
}

编译:

$ javac -d classes src/**.java
$ tree .
.
├── classes
│   └── com
│       └── pollyduan
│           └── modular
│               └── Demo.class
└── src└── com└── pollyduan└── modular└── Demo.java

打包jar并执行

$ mkdir lib

$ jar cvf lib/demo.jar -C classes .

$ java --class-path lib/demo.jar com.pollyduan.modular.Demohello modular.

--class-path 开关可以简写:

$ java -cp lib/demo.jar com.pollyduan.modular.Demo

当然我们可以为jar指定主类,来简化运行:

Main-Class: com.pollyduan.modular.Demo

需要在.MF 中增加上面一行,即可直接运行:

$ java -jar lib/demo.jar

创建模块

src/-info.java

module hello{}

我们写了一个空的模块,命名为hello。

编译模块

$ javac -d classes src/**.java

反编译看一下:

$ javap classes/module-info.class
Compiled from "module-info.java"
module hello {requires java.base;
}

为什么我们写了一个空的模块,反编译多了一行?先不用管,后面会说明为什么。

打包模块

$ jar cvf lib/hello.jar -C classes .
$ jar tf lib/hello.jar
META-INF/
META-INF/MANIFEST.MF
module-info.class
com/
com/pollyduan/
com/pollyduan/modular/
com/pollyduan/modular/Demo.class

运行模块

$ java --module-path lib -m hello/com.pollyduan.modular.Demohello modular.

这里和传统的执行jar不一样了,这里不需要,而是-path。

同样命令行可以简写成:

java -p lib -m hello/com.pollyduan.modular.Demo

模块可以增加Main-Class 吗?java9的jar提供了一个开关,用这种方式打包,可以为指定主类:

$ jar --create --file lib/lib.jar --main-class com.pollyduan.modular.Demo -C classes .

再次运行模块,命令行就会更简单了。

$ java -p lib -m hello

的设计目标

让开发者构建和维护一个大型的库或应用程序更容易;

提高平台及JDK实现的安全性和可维护性;

提升应用的性能;

在及JDK平台,让应用更小以便于部署于更小的计算单元及紧密的云部署系统。

什么是

为了解决这些问题,jdk在上层,封装了一层。

module -> package -> class/interface

那到底 是什么?

module 是一些包的容器。依赖它的应用称之为模块,模块是有名字的,其他模块使用该名字使用它。module导出特定的包,仅供依赖它的包使用。

是一个包的容器。仅仅需要导出模块依赖的包。

创建一个 声明一个

cat -info.java

module com.foo.bar{exports com.foo.bar.alpha;exports com.foo.bar.beta;
}

和-info.java 类似,它也用一个独立的java文件保存,名为 -info.java。

创建需要导出的类

暂时,类的内容不重要,可以先写一个空类,这里只列出目录结构:

$ tree .
.
├── com
│   └── foo
│       └── bar
│           ├── alpha
│           │   └── Alpha.java
│           └── beta
│               └── Beta.java
└── module-info.java

编译模块

$ javac module-info.java com/foo/bar/alpha/*java com/foo/bar/beta/*java
$ tree .
.
├── com
│   └── foo
│       └── bar
│           ├── alpha
│           │   ├── Alpha.class
│           │   └── Alpha.java
│           └── beta
│               ├── Beta.class
│               └── Beta.java
├── module-info.class
└── module-info.java

打包模块

jar cvf com.foo.bar-1.0.jar .

检查jar结构:

Java9新特性——module模块系统__Java9新特性——module模块系统

$ jar tf com.foo.bar-1.0.jar
META-INF/
META-INF/MANIFEST.MF
module-info.class
com/
com/foo/
com/foo/bar/
com/foo/bar/alpha/
com/foo/bar/alpha/Alpha.class
com/foo/bar/beta/
com/foo/bar/beta/Beta.class

引用模块

现在我们已经有了模块 com.foo.bar-1.0.jar,那么在定义其他模块,就可以使用关键字引用这个模块了。

module com.foo.app{requires co.foo.bar;requires java.sql;
}module com.foo.bar{requires com.foo.baz;exports com.foo.bar.alpha;exports com.foo.bar.beta;
}module com.foo.baz{exports com.foo.baz.mumble;
}

內建的

jdk原生的包被归并到內建的里,如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,就像以前我们不用显式的 " java.lang.*;" 一样。

这里验证了前面中,为什么反编译模块文件之后会多了一个:" 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,那么下图就不难理解了。

输入图片说明

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

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

编译时:

输入图片说明

运行时:

输入图片说明

可访问的类型

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

输入图片说明

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

输入图片说明

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

输入图片说明

在编译时,会触发异常:

输入图片说明

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

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

输入图片说明

查看內建的模块

$ 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
...

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了