module-info.java 不支持声明版本号,因 JPMS 规范禁止在模块声明中添加 version 字段,以确保模块名全局唯一、避免运行时解析冲突;替代方案包括模块路径版本目录、自动模块文件名约定、构建工具版本绑定及 SPI 服务解耦。

Java 的 module-info.java 文件本身**不支持直接声明模块版本号**,这是 JPMS(Java Platform Module System)设计上的明确限制——模块描述符只负责依赖关系、导出包、服务契约等运行时结构,版本信息被有意剥离出语法层。但这不意味着模块化项目无法做版本控制,只是需要在模块系统之外的层面协同实现。
为什么 module-info.java 不能写 version?
JPMS 规范从 Java 9 起就明确禁止在 module 声明中添加版本字段,例如以下写法是非法的:
module com.example.service@1.2.0 { ... } 或 module com.example.service version "1.2.0" { ... }
原因在于:模块名(如 com.example.service)在 JVM 中必须全局唯一且**不可重载**;若允许同名不同版本共存,会破坏模块图解析的确定性。JVM 启动时只认一个模块名,不会自动区分 v1.2.0 和 v1.3.0。
立即学习“Java免费学习笔记(深入)”;
替代方案一:用模块路径(--module-path)组织版本目录
这是最符合 JPMS 原意的实践方式。将不同版本的模块 JAR 按照约定目录结构存放,由构建工具或启动脚本显式选择加载路径。
- 目录结构示例:
mods/<br> com.example.service/1.2.0/com.example.service-1.2.0.jar<br> com.example.service/1.3.0/com.example.service-1.3.0.jar - 编译时指定精确路径:
javac --module-path mods/com.example.service/1.2.0 -d out src/module-info.java src/com/example/MyApp.java - 运行时加载特定版本:
java --module-path mods/com.example.service/1.2.0:mods/com.example.logging/2.1.0 -m com.example.app
替代方案二:利用自动模块 + 文件名版本约定
对尚未模块化的第三方库(如未含 module-info.class 的旧 JAR),JVM 会将其视为“自动模块”(Automatic Module),其模块名默认取自 JAR 文件名(去掉版本和扩展名)。
- JAR 文件命名即版本标识:
guava-32.1.3-jre.jar→ 自动模块名:guavaguava-33.0.0-jre.jar→ 自动模块名:guava(⚠️冲突!) - 安全做法:重命名 JAR,嵌入唯一标识:
guava-32.1.3-jre@stable.jar→ 模块名:guava.stableguava-33.0.0-jre@preview.jar→ 模块名:guava.preview - 在
module-info.java中按重命名后的模块名声明依赖:requires guava.stable;
替代方案三:构建工具驱动的版本绑定(Maven/Gradle)
虽然 module-info.java 不写版本,但构建工具可在编译期注入、校验并隔离依赖版本。
- Maven 中通过
<artifactid></artifactid>+<version></version>确保依赖分辨率,再映射为模块路径:
<dependency><br> <groupId>com.example</groupId><br> <artifactId>service-module</artifactId><br> <version>1.2.0</version><br> </dependency> - 使用 Maven 插件生成模块路径清单(如
maven-dependency-plugin输出mods/目录) - Gradle 可配置
javaPlatform统一管理模块 BOM(Bill of Materials),约束跨模块版本一致性
替代方案四:服务接口 + 模块提供者解耦版本
当多个模块实现同一功能(如日志、序列化),可用 SPI(Service Provider Interface)机制隐藏具体版本。
- 定义标准服务接口模块(无版本敏感):
module com.example.spi { exports com.example.spi; } - 各版本实现模块分别提供:
module com.example.impl.v1 { requires com.example.spi; provides com.example.spi.Logger with com.example.impl.v1.Slf4jAdapter; }module com.example.impl.v2 { requires com.example.spi; provides com.example.spi.Logger with com.example.impl.v2.Log4j2Adapter; } - 主模块只依赖 SPI,运行时由 JVM 自动发现并加载 —— 版本切换只需替换实现模块 JAR



















