1. 为什么Java需要模块化?
2008年我刚接触Java开发时,一个典型的企业级应用往往要依赖上百个JAR包。记得有次为了排查ClassNotFoundException,我花了整整两天时间在几十个相互嵌套的依赖中寻找缺失的类。这种"JAR地狱"(JAR Hell)正是Java模块化要解决的核心问题之一。
Java模块化系统(JPMS)在Java 9中正式引入,它从根本上改变了Java代码的组织方式。传统Java应用的类路径(Classpath)就像把所有食材倒进一口大锅——你无法控制谁可以访问什么,也无法明确声明各个组件间的依赖关系。而模块系统则像专业的厨房备餐台,每个食材都有专属位置和明确的取用规则。
关键区别:Classpath是平铺的命名空间,所有可见的类都能被任意访问;Modulepath是层次化的,必须显式声明哪些包可以被外部访问。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 模块化的核心概念解析
2.1 模块描述文件(module-info.java)
每个Java模块的核心是位于源代码根目录的module-info.java文件。这个文件定义了三个关键要素:
java复制module com.example.myapp {
requires java.sql; // 声明依赖
exports com.example.dao; // 暴露指定包
opens com.example.model; // 允许反射访问
}
我在实际项目中遇到过典型的配置错误:当模块A需要访问模块B的内部API时,如果模块B没有通过opens显式开放包,即使设置了--add-opens运行时参数也会失败。正确的做法是在模块B的声明中:
java复制module B {
opens com.example.internal to A;
}
2.2 模块路径 vs 类路径
模块系统引入了全新的类加载机制:
- 模块路径(Modulepath):只包含已模块化的JAR
- 类路径(Classpath):传统方式,所有类都在未命名模块中
混合使用时有个重要特性:类路径上的所有代码会自动归属到"未命名模块",这个模块会读取所有其他模块,但自身不能被其他模块读取。这解释了为什么旧库
