开会员与付费前请必须阅读这篇文章,在首页置顶第一篇:(进站必看本站VIP介绍/购买须知)
本站所有源码均为自动秒发货,默认(百度网盘)
本站所有源码均为自动秒发货,默认(百度网盘)
在 Java 9 之前,我们一直使用的是 ** 类路径(Classpath)** 机制来管理依赖,虽然简单易用,但也带来了诸多痛点:依赖冲突、jar 包冲突、无法控制访问权限、启动加载冗余类等问题。
为了解决这些问题,Oracle 在 Java 9 中正式推出了Java 模块化系统(Jigsaw 项目),它是 Java 平台自诞生以来最重大的架构变革之一。
本文将带你从零入门 Java 模块化系统,包含核心概念、手动搭建模块化项目、IDEA 实战、模块化依赖配置、访问权限控制等实战内容,适合 Java 开发者学习、项目重构使用,全文可直接发布 CSDN。
一、为什么需要 Java 模块化?
1.1 传统 Classpath 的痛点
- 依赖地狱:多个版本的 jar 包共存,容易出现类冲突、方法找不到等问题;
- 访问失控:
public就是全局公开,无法对外部隐藏内部实现类; - 启动臃肿:JVM 启动时会加载所有类,哪怕你只用到一小部分;
- 无法封装:工具类、内部 API 被随意调用,代码安全性差。
1.2 模块化带来的核心优势
- 强封装性:严格控制类的访问权限,只暴露想暴露的接口;
- 依赖管理:声明式依赖,明确模块间依赖关系,避免冲突;
- 可裁剪 JDK:使用
jlink打包最小运行时镜像,体积大幅缩小; - 程序健壮性:编译期检查依赖,提前发现问题,而非运行时崩溃。
二、模块化核心概念
2.1 什么是模块?
模块 = 代码 + 配置文件(module-info.java)
它是比 Jar 包更大的代码组织单元,一个模块包含多个包,通过
module-info.java声明:- 我依赖谁
- 我暴露哪些包给外部使用
- 我提供哪些服务
- 我使用哪些服务
2.2 核心关键字
表格
| 关键字 | 作用 |
|---|---|
module |
定义一个模块 |
requires |
声明依赖其他模块 |
exports |
暴露包给其他模块访问 |
requires transitive |
传递依赖(隐式传递给下游模块) |
opens |
开放包给反射使用(框架必备) |
provides ... with |
服务提供 |
uses |
服务消费 |
2.3 模块命名规范
- 全小写,使用域名倒置(如
com.example.demo) - 不要使用
module、java、javax开头(JDK 保留)
三、环境准备
- JDK 9+(本文使用JDK 17,LTS 版本,企业主流)
- IDEA 2021+(完美支持模块化)
- Maven/Gradle(可选,本文先纯手工搭建,再讲 Maven 集成)
四、手动搭建第一个模块化项目(零基础入门)
我们创建两个模块,模拟模块间依赖与调用:
module-common:公共模块,提供工具类module-user:业务模块,依赖 common 模块
4.1 项目结构(必须严格遵守)
模块化项目的核心:src 目录下直接放包 + module-info.java
plaintext
java-modular-demo/
├── module-common/
│ └── src/
│ ├── com/
│ │ └── example/
│ │ └── common/
│ │ └── StringUtils.java # 工具类
│ └── module-info.java # 模块描述文件
└── module-user/
└── src/
├── com/
│ └── example/
│ └── user/
│ └── UserService.java # 业务类
└── module-info.java # 模块描述文件
4.2 编写 module-common 模块
1. 工具类 StringUtils.java
java
运行
package com.example.common;
/**
* 公共工具类
*/
public class StringUtils {
/**
* 判断字符串是否为空
*/
public static boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}
}
2. 模块描述文件 module-info.java
java
运行
// 定义模块名
module module.common {
// 暴露包给外部模块访问
exports com.example.common;
}
4.3 编写 module-user 模块
1. 业务类 UserService.java
java
运行
package com.example.user;
import com.example.common.StringUtils;
/**
* 用户业务类
*/
public class UserService {
public static void main(String[] args) {
String name = "Java模块化";
// 调用公共模块的工具类
if (StringUtils.isEmpty(name)) {
System.out.println("用户名为空");
} else {
System.out.println("用户名:" + name);
}
}
}
2. 模块描述文件 module-info.java
java
运行
// 定义模块名
module module.user {
// 依赖公共模块
requires module.common;
}
4.4 运行测试
直接运行
UserService,控制台输出:plaintext
用户名:Java模块化
✅ 运行成功!模块化项目搭建完成
五、模块化核心特性实战
5.1 访问权限控制(封装性)
如果我们不使用 exports,其他模块无法访问该包下的类,哪怕是
public。示例:在
module-common中创建一个内部包,不暴露:plaintext
com.example.common.internal/
└── InternalUtil.java
module-info.java不导出这个包:java
运行
module module.common {
exports com.example.common;
// 不导出 com.example.common.internal
}
此时
module-user无法导入InternalUtil,编译直接报错,实现了真正的封装!5.2 传递依赖 requires transitive
场景:A 依赖 B,B 依赖 C,A 想直接使用 C,无需重复声明
requires C。示例:
java
运行
// module.common 模块
module module.common {
requires transitive module.core;
exports com.example.common;
}
// module.user 模块
module module.user {
requires module.common;
// 无需 requires module.core,自动继承传递依赖
}
5.3 反射兼容 opens
Spring、MyBatis 等框架大量使用反射,模块化默认禁止反射访问非导出包,必须用
opens声明:java
运行
// 开放指定包给反射使用
opens com.example.user.service;
// 开放整个模块给反射使用(不推荐,不安全)
open module module.user {
}
5.4 服务发现 provides/uses
模块化提供了标准的SPI 服务发现机制,替代传统
ServiceLoader。- 服务接口模块:定义接口
- 服务实现模块:
provides 接口 with 实现类 - 服务调用模块:
uses 接口
六、IDEA + Maven 搭建模块化项目
企业开发基本都用 Maven,这里给出标准配置:
6.1 父 pom.xml
xml
<modules>
<module>module-common</module>
<module>module-user</module>
</modules>
<packaging>pom</packaging>
6.2 子模块 pom.xml
无需特殊配置,保持默认,IDEA 会自动识别
module-info.java。6.3 注意事项
- Maven 依赖 ≠ 模块化依赖
- 必须在
module-info.java中声明requires,否则编译报错 - 依赖的 jar 包如果没有模块化,会变成自动模块(模块名 = 文件名)
七、使用 jlink 打包最小运行时镜像
模块化最大的亮点:打包只包含项目用到的 JDK 模块,体积从几百 MB 降到几十 MB!
7.1 打包命令
bash
运行
jlink
--module-path out/production
--add-modules module.user
--output myapp
--strip-debug
--compress 2
--no-header-files
--no-man-pages
7.2 运行
bash
运行
myapp/bin/java -m module.user/com.example.user.UserService
✅ 打包后体积仅 20MB 左右,传统方式打包需要 JDK 环境,而
jlink打包后开箱即用!八、模块化常见问题与解决方案
8.1 错误:模块未找到
原因:
requires模块名写错,或依赖未添加
解决:检查module-info.java + 项目依赖
8.2 错误:类无法访问
原因:包未使用
exports暴露
解决:在模块描述文件中添加exports 包名
8.3 框架反射报错
原因:模块化禁止反射访问未开放包
解决:使用opens 包名开放反射权限
8.4 第三方 Jar 无模块信息
解决:
- 自动模块:
requires jar包名 - 手动生成模块描述文件
九、总结
Java 模块化系统(Jigsaw)是 Java 现代化的核心特性,它解决了传统 Classpath 的所有痛点,让 Java 项目更健壮、安全、轻量。
本文核心知识点:
- 模块 = 代码 +
module-info.java - 三大核心:
requires(依赖)、exports(暴露)、opens(反射) - 严格的访问控制,真正实现代码封装
jlink打包最小运行时,适合云原生、微服务部署
建议:新项目直接使用模块化,老项目逐步重构,拥抱 Java 现代化开发!