JSR 376提议的Java模块化方式,在Java 9中发布,适时跟进一下。

目标

先来看下JSR 376的目标,可以简要概况为,

  • 让Java在不同类型的计算设备上更适配、易裁剪
  • 提高代码安全性与可维护性
  • 提升应用性能

实现

直接观察JDK代码结构,JDK 9里对原有代码进行了模块化切分。大致浏览下代码目录,可以看到Java Module信息如何定义。

module-info.java文件中定义了Module信息,比如,

module java.base {
    exports java.io;
    exports jdk.internal.jmod to 
        jdk.compiler,
        jdk.jlink;
    uses java.lang.System.LoggerFinder;
    provides java.nio.file.spi.FileSystemProvider with jdk.internal.jrtfs.JrtFileSystemProvider;
}

module java.se {
    requires transitive java.compiler;
}

module java.desktop {
    opens javax.swing.plaf.basic to jdk.jconsole;
}

在model-info.java里面引入了exportsmoduleopenopensprovidesrequiresuseswithtotransitive关键字。

module

module {module-name}用于定义当前module-info.java描述的module的名称。

exports

exports {package-name}、exports {package-name} to {module-name},用于声明当前模块下的哪些package被导出。

requires

requires {module-name}requires transitive {module-name}用于声明当前模块依赖哪些模块,transitive用于表明这种依赖是否可传递。

provides

provides {interface-name} with {class-name}用于声明当前module是一个service提供者,提供了interface-name接口定义的具体实现。

uses

uses {interface-name}声明当前模块使用了指定名称的service,当前模块为对应service的使用者。

JDK文档中可以查看java.util.ServiceLoader<S>来看具体的service相关概念与实现机制。

open

opens {package-name} to {module-name}声明当前模块将指定package开放给对应的其它模块。在之前的Java中,通过反射可以后去任意类的成员与函数,加上这个声明之后只有指定模块中的代码才可以进行相应访问。

总结

上面只是简要的看了下Java中的模块怎么定义,通过新提供的这些model-info.java中关键字的功能,可以看到除了模块化定义本身之外,之前几个概念与用法发生了相应变化。

首先是publicprotectedprivate等描述符的含义发生了变化,public也有了约束,必须模块间显示进行了声明,否则也是无法访问的。

其次是反射接口的能力,先前可以进行的操作,现在加上了opens ... to ...这样的模块定义约束。动态能力得到了控制,从接口提供角度来说,避免了不应该的暴露。

实际项目中去使用这套模块机制,大的方向还是很明确的,就是拆分模块。没有这套机制,良好的代码组织也会进行模块切分,估计会比较容易得到应用。

参考