模块化系统(JPMS)
Java 9 引入了模块化系统(Java Platform Module System,简称 JPMS),这是 Java 历史上最大的变化之一。
但说实话,这东西挺难理解的。我当年学的时候,看了半天 module-info.java 也不知道怎么写。
今天我们就来把模块化系统彻底讲清楚。
一、为什么需要模块化
1.1 之前的问题:类路径的黑暗时代
在 Java 9 之前,所有类都在类路径(classpath)里:
问题:
- JAR Hell:多个版本的同一 JAR 在 classpath
- 无封装:任何代码都可以访问
java.lang.reflect等内部 API - 启动慢:JVM 启动要加载所有类,不知道模块依赖
1.2 模块化的目标
模块化的三个目标:
- 可靠的配置:显式声明模块依赖
- 强封装:隐藏内部实现,只暴露公开 API
- 可扩展:应用可以扩展平台模块
二、module-info.java 的基本结构
2.1 语法
2.2 简单示例
三、核心关键字
3.1 requires:声明依赖
3.2 exports:导出包
3.3 uses 和 provides:服务接口
这允许模块定义接口,实现类在另一个模块,运行时动态加载。
四、内置模块
4.1 查看可用模块
4.2 常用模块
五、【直观类比】
【直观类比】
模块化就像一个公司的部门:
每个部门只知道自己需要什么部门,不需要知道内部细节。
六、模块路径 vs 类路径
6.1 区别
6.2 unnamed module 和 automatic module
七、生产避坑
7.1 ❌ 错误示范:导出太多包
正确做法:
7.2 ❌ 错误示范:忘记 transitive
7.3 ❌ 错误示范:访问未导出的模块
正确做法:让模块显式导出:
八、面试追问链
第一层:基础概念
面试官问:"什么是 Java 模块化?"
Java 9 引入的模块系统,通过 module-info.java 声明模块名、依赖、导出等。可以显式声明模块间的依赖关系,提供更强的封装性。
第二层:关键字
面试官问:"requires 和 exports 有什么区别?"
requires 声明依赖的模块,exports 声明导出的包。requires 告诉 JVM "我需要这个模块才能编译/运行",exports 告诉 JVM "这个包可以被其他模块访问"。
第三层:迁移
面试官问:"如何从老项目迁移到模块化?"
可以先用 automatic module 方式,让老 JAR 自动成为模块。然后逐步给每个模块添加 module-info.java,显式声明依赖和导出。
【学习小结】
- 模块化通过 module-info.java 声明
- requires 声明依赖,exports 导出包
- uses/provides 实现服务发现
- 类路径上的老 JAR 是 unnamed module
- 模块路径提供更强的封装性
- 可以逐步迁移到模块化