个人博客 转载请注明原创出处。
从Java 9
开始,在Java
的世界里多了一个叫模块(JSR376)的特性。模块系统的前身是Jigsaw
项目。最初,该项目仅仅是为JDK
设计、实现一个模块系统。后来项目组也但愿它能为开发者所用——虽然,一开始它并非Java SE
平台规范的组成部分。随着项目的不断深刻,Java
平台对标准模块系统的呼求也日益增加,JCP
批准该项目升级为JavaSE
平台的一部分,也能服务于Java ME
和Java EE
平台的需求。java
Java
平台模块系统是这样描述的:Java
编程组件,即模块。它是自描述的代码与数据的集合,有如下特性:javac
、jlink
增长了一些选项,以及在Java
中,你能够指定模块路径,这些路径定位模块的定义。JAR
文件,该文件是一个JAR
文件,其根目录中包含module-info.class
文件。JMOD
格式,它是一种相似于JAR
的打包格式,但它能够包含原生代码和配置文件。使你可以将JDK
的模块组合成各类配置,包括:编程
JRE
和JDK
同样的配置。Java SE 8
中定义的每一个压缩配置文件的内容大体相同。JDK
和JRE
运行时镜像以适应模块并提升性能、安全性和可维护性。URI
方案,用于命名存储在运行时映像中的模块,类和资源,而不会泄露映像的内部结构或格式。Java
运行时镜像中删除rt.jar
和tools.jar
。JDK
的内部API
都不可访问,但在全部或大部分功能都支持替换以前,能够访问一些关键的、普遍使用的内部API
。运行jdeps -jdkinternals
命令以肯定你的的代码是否使用了内部JDK API
。安全
先来讲说模块系统的兼容性。Java一直是比较保守的,体如今更新上就是良好的兼容性。虽然看了官方对Java
平台模块系统的描述好像改动很是大,可是你的旧项目即便不模块化也是能在新JDK
上运行的。后面会讲到没有模块化的类包是如何与模块交互的。框架
既然不模块化也能好好的运行,那么为何要这么大费周章的折腾代码呢?ide
第一点,Java 9
前的Java
程序,即便是一个简单的输出Hello World
的程序,也必须将整个JDK
、JRE
运行时镜像打包进去才能运行,这时Java
引觉得傲的数量繁多的类库反而成了累赘。好比开源的优秀编程库——Guava
里有不少很实用的工具类,有时咱们可能只用到了其中一个类而已,却不得不将整个Guava
类库打包进咱们的项目。模块化
第二点,无法定义类是否能被其余包里的类引用到。好比咱们编写了一个工具类,若是但愿这个类只能被某些包里的其余类引用到,不暴露给其余包,Java 9
前的Java
程序是作不到这一点的。工具
模块化一个项目只要在项目的根目录建立一个module-info.class
文件就能够了。性能
如图所示,咱们建立了一个名为module
的模块并用关键字exports
导出了test
包。若是有其余模块导入module
模块就能够引用到Main
类了,值得注意的是和test
同级的包和test
内部的包由于没有被导出,都是不能被引用到的。优化
而引用一个模块则是用关键字requires
:ui
而后就可使用test
包内的类了:
import test.Main; /** * @author Yuicon */ public class Test { public static void main(String[] args) { Main main = new Main(); System.out.println(main); } }
不过在导入前还须要在模块依赖里添加要导入的模块:
java.base
模块是默认导入的,里面有咱们经常使用的类库:
咱们知道模块化后就能控制那些包能够被引用到了。不过不止如此,一个模块的类是不能访问到其余模块里的类的私有属性的。听起来好像是理所固然的,这是由于原先咱们是能够用反射来访问到私有属性的。模块化后就算反射也不能访问到了,算是增强了安全性。
不过这样的话,那些依赖反射来获取私有属性的框架和库就倒霉了。为了兼容这些框架和库,咱们能够在模块定义里加一个关键字open
:
module-info.class open module module { exports test; }
这样咱们就声明了一个开放的模块,在模块的全部软件包上授予深刻的反射访问权限(访问公共和私有API)。
在模块声明文件里一共有五种模块语句,分别是:
package test.driver; /** * @author Yuicon */ public interface Driver { int getCode(); }
package test; import test.driver.Driver; /** * @author Yuicon */ public class DriverImpl implements Driver { @Override public int getCode() { return 10086; } }
module module { exports test.driver; // 导出包 provides Driver with DriverImpl; // 为接口Driver提供实现 }
module queue { requires module; // 导入包 opens test; // 开放包的反射权限 uses Driver; // 声明使用接口 }
package main; import test.driver.Driver; import java.util.ServiceLoader; /** * @author Yuicon */ public class Main { public static void main(String[] args) { // 获取实现 ServiceLoader<Driver> serviceLoader = ServiceLoader.load(Driver.class); serviceLoader.findFirst().ifPresent(driver -> System.out.println(driver.getCode())); } } 输出: 10086 Process finished with exit code 0
你能够建立一个不包含任何代码的模块,它收集并从新导出其余模块的内容,这样的模块称为聚合模块。假设有几个模块依赖于五个模块,你能够为这五个模块建立一个聚合模块。如今,你的模块只能依赖于一个模块——聚合模块。
为了方便,Java 9
包含几个聚合模块,如java.se
和java.se.ee
。java.se
模块收集Java SE
的不与Java EE
重叠的部分。java.se.ee
模块收集组成Java SE
的全部模块,包括与Java EE
重叠的模块。