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 尚未大力支持
- Java 模块化系统尚未成熟,存在较多变化
- 已有的模块系统 OSGi
- OSGi, Open Service Gateway Initiative, https://www.osgi.org/
- 在 OSGi 容器里面运行 bundle,通过类加载器来控制类的可见性
- Java 模块化 vs OSGi
- Java 更偏源头控制,从 JDK 开始分模块开发和部署
- OSGi 更偏动态性控制,对 bundle 进行全生命周期控制
- Java 模块化更年轻,尚未成熟,OSGi 已经发展多年,更完整
- 两者互相借鉴和互操作
- https://www.infoq.com/articles/java9-osgi-future-modularity/