MOOC 个人学习笔记

# 1. 模块化概述

# Jar Hell

  • jar 文件无法控制别人访问其内部的 public 的类
  • 无法控制不同 jar 包中,相同的类名 (包名 + 类名)
  • Java 运行时,无法判定 classpath 路径上的 jar 中有多少个不同版本的文件。Java 加载第一个符合名字的类
  • Java 运行时,无法预判 classpath 路径上是否缺失了一些关键类

# 模块化系统

  • 模块化必须遵循的三个原则
    • 强封装性:一个模块必须能够对其他模块隐藏其部分代码
    • 定义良好的接口:模块必须向其他模块公开定义良好且稳定的接口
    • 显式依赖:明确一个模块需要哪些模块的支持才能完成工作

# Jigsaw 拼图

  • Java 9 开始引入新的模块化系统:Jigsaw 拼图
  • 以模块 (module) 为中心
  • 对 JDK 本身进行模块化
  • 提供一个应用程序可以使用的模块系统
  • 优点
    • 可靠的配置
    • 强封装性
    • 可扩展开发
    • 安全性
    • 性能优化

# 2. 模块创建和运行

# Java Jigsaw

  • 自 Java 9 推出,以模块为中心
  • 在模块中,仍以包 - 类文件结构存在
  • 每个模块中,都有一个 module-info.java
    • 说明这个模块依赖哪些其他的模块,输出本模块中哪些内容
module java.prefs {
    requires java.xml;
    
    exports java.util.prefs;
}

# 命令行创建

  • 新建一个项目主目录,如 F:\temp\JavaModuleTest
  • 创建 src 目录 (放 java),modules 目录 (放 class),lib 目录 (放 jar)
  • 在 src 下面建立一个目录 module.hello (模块名字,可自由定)
  • 在 module.hello 目录下,建立 cn\hello 目录,再建立 HelloWorld.java
  • 在 module.hello 目录下,建立一个 module-info.java
  • 编译 / 运行 / 打包
  • 链接 jlink,制作自定义运行时映像 (custom runtime image)
    • 舍弃无用庞大的 JDK 库
    • 适合在容器中快速部署运行

# Eclipse 创建

  • 新建一个 Java Project 项目主目录
    • 可以在创建的时候,直接选择创建 module-info.java
    • 或者选中项目,右键 configure 选择 Create module-info.java
  • 创建 cn.hello.HelloWorld.java
    • 可以选择在默认 src 目录下
    • 可以新建一个 source folder,取名 module.hello,再创建包结构和类文件
  • 修改 module-info.java
  • 编译 / 运行 / 打包

# 注意事项

  • Java Module 和 Maven Multi Module 不一样
  • 使用 JDK 9+,不强制创建 Java Module,即不创建 module-info.java
  • Module 的命名是由 module-info.java 来控制
    • requires
    • exports

# 3. 模块信息文件

# module-info.java

  • 模块安全控制的核心
  • 是模块和外界沟通的总负责
  • 名字和内容组成
  • 模块名字
    • 模块名称必须唯一
    • 可以不和包名相同
    • 使用有代表性的词语
    • 不需要包括版本号

# requires 调用其他的模块

  • java --list-modules 查看系统提供的模块
  • java --describe-module 看某一个模块
  • requires 可以添加多个
  • 单纯 requires,模块依赖不会传递
  • requires N, 编译和运行都依赖于 N
  • requires transitive N,编译和运行都传递依赖于 N
  • requires static N,编译依赖于 N,运行可选
  • requires transitive static N,编译传递依赖于 N,运行可选

# exports 输出当前模块

  • 只有输出,别人才能使用
  • exports 可以指定某些包输出
    • exports <package>
  • 限定输出到特定的模块使用
    • exports <package> to <module1>, <module2>;

# opens 将当前模块开放用于反射

  • exports 导出的包的 public 部分可以反射,其他权限修饰的内容和未导出的内容无法反射 (setAccessible (true) 也无效)
  • opens 可以打开一些包,其他模块可以反射调用这些包及内容
  • open module 打开整个模块
  • 打开一个包
    • opens <package>
  • 仅对某些模块打开一个包
    • opens <package> to <module1>, <module2>;

# 4. 服务

  • Java 模块系统引入的新功能,实现解耦
  • 模块对外只暴露接口,隐藏实现类
  • provides 提供接口,with 实现类 (不导出)
  • uses 消费接口
  • ServiceLoader 加载接口的实现类
module module.first {
    exprots first.p1;
    provides first.p1.Shoe with first.p2.DoubleStar;
}
module module.second {
    requires module.first;
    uses first.p1.Shoe;
}
ServiceLoader<Shoe> objs = ServerLoader.load(Shoe.class);
for(Shoe obj : objs) {
    obj.walk();
}
  • ServiceLoader 通过 load 加载接口的实现类 (with 语句提供)
  • 每次 load,(默认情况下) 都会产生新的各自独享的实例,没有唯一的服务实例
  • 可以调用 reload 进行刷新

  • Java 模块系统提供两种方法创建服务实例
    • 服务实现类有 public 的无参构造函数
    • 使用单独的静态提供者方法
      • 一个名为 provider 的 public static 无参数方法
      • 返回服务接口或子类
provides first.p1.Shoe with first.p1.ShoeFactory;
public class ShoeFactory {
    public static Shoe provider() {
        Shoe result = new Shoe();
        return result;
    }
}

# 5.Java 模块化应用

  • Java 模块化系统 (Java 9+)
    • 从根源上对 JDK 进行模块化,降低最终程序运行时负载
    • 在 jar 层上增加一个 module 机制
    • 引入 exports/requires/opens 明确模块边界和依赖关系,程序更隐私安全
    • 引入服务 provides/uses 使得程序更解耦
    • jlink 制作运行时映像,使运维更高效
  • 向 Java 模块化系统迁移的制约因素
    • Java 模块化系统尚未成熟,存在较多变化
      • 只有 11 是 LTS,9/10/12/13 均是 STS
    • Java 9+ JDK 版权收费,很多程序员和厂商还是使用 Java 8
    • 已有的庞大的第三方库,基本不是基于模块开发的,完全融入或使用模块重新开发有困难
    • 构建工具和开发工具 IDE 尚未大力支持
  • 已有的模块系统 OSGi
    • OSGi, Open Service Gateway Initiative, https://www.osgi.org/
    • 在 OSGi 容器里面运行 bundle,通过类加载器来控制类的可见性
  • Java 模块化 vs OSGi