Java模块化(Jigsaw)不替代FatJar,而是通过module-info.java实现强封装与显式依赖,配合--module-path分层部署,使依赖可选、版本共存、更新原子,提升部署灵活性。

Java原生模块化(Jigsaw,自JDK 9引入)本身不直接替代FatJar,也不能“提升对象变量部署灵活性”——这个说法存在概念混淆。“对象变量”是运行时内存中的实例,与打包部署方式无直接关系;真正影响部署灵活性的是依赖组织方式、类加载机制和运行时环境解耦能力。
准确来说,应聚焦于:如何利用Java模块系统(JPMS)配合分层部署策略,替代传统FatJar,实现更精细、可复用、易升级的部署结构。
以下是关键路径与实操要点:
明确模块化在部署中的定位
- JPMS核心价值是编译期和运行期的强封装 + 显式依赖声明(
module-info.java),它不负责打包格式,也不自动压缩或分离jar。 - 它必须与构建工具(Maven/Gradle)和部署策略协同使用,才能发挥部署优势。
- 单纯加
module-info.java而仍打FatJar,几乎不带来部署收益。
构建可模块化部署的项目结构
- 每个业务组件或公共库独立成模块(如
com.example.api、com.example.service),各自声明requires和exports。 - 主应用模块(如
com.example.app)只requires必要模块,不强制拉取全量依赖。 - 使用Maven的
maven-jar-plugin配置<archive><index>true</index></archive>,生成模块化JAR(含MANIFEST.MF中Automatic-Module-Name或完整module-info.class)。
部署时放弃FatJar,改用模块路径(--module-path)启动
java --module-path "lib/*:modules/*" \
--module com.example.app/com.example.app.Main-
lib/放第三方模块化JAR(如Spring Boot 3.x+已支持JPMS的starter) -
modules/放自研模块JAR - 启动不再依赖
-cp或FatJar内嵌逻辑,所有依赖显式、可替换、可版本共存
结合Spring Boot 3+实现轻量可插拔部署
- Spring Boot 3基于Jakarta EE 9+和JDK 17+,天然支持模块化。
- 移除
spring-boot-maven-plugin的默认repackage,改用普通jar打包:<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <layout>ZIP</layout> <!-- 不要设为默认,禁用fat jar --> <executable>false</executable> </configuration> </plugin> - 依赖统一放在外部
lib/目录,通过--module-path加载,主jar仅含自身字节码与资源。 - 效果:主应用jar从100MB→2–5MB;更新某个SDK只需替换对应模块jar,无需重打整个FatJar。
注意实际约束与避坑点
- 并非所有依赖都已模块化:大量老库(如Logback、HikariCP旧版)仍是自动模块(
Automatic-Module-Name),需手动适配或保留classpath兼容模式。 - Spring Boot的自动配置机制依赖类路径扫描,模块化后需确保
spring.factories资源在模块opens或uses声明中暴露,否则@EnableAutoConfiguration失效。 - JVM参数需同步调整:
--add-opens java.base/java.lang=ALL-UNNAMED等可能仍需保留,尤其涉及反射的框架代码。 - Docker镜像中建议使用多阶段构建,将
jlink定制最小JRE(仅含所需模块),再叠加你的模块jar,进一步压缩体积与攻击面。
本质上,这不是“用模块化替代FatJar”,而是以模块化为设计契约,驱动部署从“打包即交付”转向“声明即部署”——依赖可选、版本可并存、更新可原子,这才是真正的灵活性来源。
立即学习“Java免费学习笔记(深入)”;


















