Java 模块化系统(JPMS)
在介绍一个
Java 模块化系统(JPMS)
一、理论说明
1. 模块化的定义
Java 模块化系统(Java Platform Module System, JPMS)是 Java 9 引入的一项重大特性,它为 Java 平台和应用程序提供了模块化架构。模块化允许将代码组织成独立的模块单元,每个模块明确声明其依赖关系和对外暴露的 API,从而提高代码的可维护性、安全性和可扩展性。
2. 模块化与传统 JAR 的区别
特性 | 传统 JAR | 模块化 JAR |
---|---|---|
结构 | 类的集合,无明确边界 | 显式声明模块名、依赖和导出 |
依赖管理 | 全路径类名,容易冲突 | 显式声明 requires ,编译时检查 |
访问控制 | 仅包可见性(public /protected ) | 模块级导出(exports ),更精细控制 |
加载机制 | 全盘加载所有 JAR | 基于模块图,按需加载 |
安全性 | 类路径污染风险 | 更严格的访问控制,减少反射滥用 |
二、核心概念
1. 模块声明(module-info.java
)
每个模块必须包含一个 module-info.java
文件,用于声明模块名、依赖和导出的包。
// module-info.java
module com.example.myapp {// 声明依赖的模块requires java.base;requires java.sql;// 导出包供其他模块使用exports com.example.api;// 可选:仅允许特定模块访问exports com.example.internal to com.example.client;// 声明服务提供者provides com.example.Service with com.example.impl.ServiceImpl;// 使用服务uses com.example.Service;
}
2. 模块路径(Module Path)
模块化系统引入了新的类路径概念 —— 模块路径,用于替代传统的类路径(Classpath)。模块路径上的 JAR 文件必须是模块化的(包含 module-info.class
)。
# 编译模块化应用
javac --module-path mods -d out $(find src -name "*.java")# 运行模块化应用
java --module-path mods --module com.example.myapp/com.example.Main
三、模块类型
1. 命名模块(Named Modules)
显式声明了 module-info.java
的模块,如:
module com.example.util {exports com.example.util;
}
2. 自动模块(Automatic Modules)
传统 JAR 文件在模块路径上会被自动转换为自动模块,模块名由 JAR 文件名推导(如 my-library-1.0.jar
变为 my.library
)。自动模块隐式导出所有包,依赖所有其他模块。
3. 系统模块(System Modules)
Java 平台自身的模块(如 java.base
、java.sql
),由 JDK 提供。
四、服务机制(Service)
模块系统提供了服务发现机制,允许模块声明和使用服务接口,解耦服务提供者和使用者。
1. 定义服务接口
// com.example.api.Service.java
package com.example.api;public interface Service {void execute();
}
2. 实现服务
// com.example.impl.ServiceImpl.java
package com.example.impl;import com.example.api.Service;public class ServiceImpl implements Service {@Overridepublic void execute() {System.out.println("执行服务");}
}
3. 声明服务提供者
在提供者模块的 module-info.java
中声明:
module com.example.impl {exports com.example.impl;provides com.example.api.Service with com.example.impl.ServiceImpl;
}
4. 使用服务
在使用者模块中通过 ServiceLoader
加载服务:
import com.example.api.Service;
import java.util.ServiceLoader;public class Main {public static void main(String[] args) {ServiceLoader<Service> loader = ServiceLoader.load(Service.class);loader.forEach(Service::execute);}
}
五、模块化优势
1. 强封装性
模块仅导出明确声明的包,内部实现对外部不可见,减少了意外依赖。
2. 依赖清晰
模块间依赖显式声明,编译时检查,避免类路径冲突和版本地狱。
3. 性能优化
JVM 可以基于模块图进行更高效的类加载和资源分配。
4. 安全性增强
通过限制反射访问和更严格的访问控制,减少安全漏洞。
5. 可维护性提升
代码按功能划分为独立模块,便于团队协作和系统演进。
六、应用实例
1. 创建简单模块化应用
假设有两个模块:com.example.api
和 com.example.impl
。
com.example.api
模块
// module-info.java
module com.example.api {exports com.example.api;
}// com.example.api.Greeting.java
package com.example.api;public interface Greeting {String sayHello();
}
com.example.impl
模块
// module-info.java
module com.example.impl {requires com.example.api;exports com.example.impl;
}// com.example.impl.EnglishGreeting.java
package com.example.impl;import com.example.api.Greeting;public class EnglishGreeting implements Greeting {@Overridepublic String sayHello() {return "Hello, World!";}
}
编译和运行
# 编译模块
javac -d api-module src/api/module-info.java src/api/com/example/api/*.java
javac --module-path api-module -d impl-module src/impl/module-info.java src/impl/com/example/impl/*.java# 运行应用
java --module-path api-module:impl-module -m com.example.impl/com.example.impl.Main
七、面试题
题目;
答案:
八、自我总结
Java 模块化系统(JPMS)为大型应用和平台提供了更现代的架构模式,通过显式的模块定义和依赖管理,解决了传统 Java 项目中的类路径混乱、依赖冲突和封装不足等问题。关键要点包括:
- 模块声明:使用
module-info.java
定义模块边界和依赖关系。 - 服务机制:通过
ServiceLoader
实现松耦合的服务发现。 - 模块路径:替代传统类路径,提供更严格的依赖管理。
- 兼容性:支持与传统 JAR 文件混合使用(自动模块)。
在实际应用中,模块化适合大型项目和框架开发,能够显著提高代码质量和可维护性。但对于小型应用,可能会增加额外的复杂度,需权衡使用。JPMS 是 Java 平台向现代化演进的重要一步,也是未来 Java 生态系统的基础。