1. 进入Java模块化与Jigsaw的世界
1.1 为什么需要Java模块化
在现代Java开发中,模块化开发能够将系统拆解为独立的、可重复使用的模块,提升封装性与可维护性。通过引入Jigsaw,Java在版本9后引入了平台模块系统,实现了对依赖的显式声明和对API的可控暴露。
如果你是零基础起步,先理解两个核心概念:module表示一个独立的模组,module-path是加载模块的路径,与传统的classpath不同,模块之间的依赖关系通过module-info.java进行显式描述。掌握这些,将帮助你快速从入门进入实战开发。
2. 环境搭建与工具准备
2.1 安装并验证JDK版本
要开始模块化开发,首要任务是准备一个支持Java模块系统的JDK版本,最好选择Java 9及以上的版本。安装完成后,使用下面的命令核实环境是否就绪:java -version、javac -version。

java -version
javac -version
如果你使用集成开发环境(IDE),如IntelliJ IDEA或VS Code,请确认已开启对模块化的支持,并在新建项目时选择相应的模板。通过IDE可以直观地创建module-info.java以及模块结构,降低初学门槛。
3. 第一个模块化项目的搭建与理解
3.1 构建简单的模块化结构:util 与 app
为了让零基础同学快速上手,我们先创建一个最小的两模块示例:util模块提供工具,app模块依赖于它并包含入口程序。关键点在于通过module-info.java来声明关系、暴露包与导入依赖。
在这个示例中,util导出包,app通过requires导入该模块。接下来我们给出核心代码结构和必要的配置文件,以便你在本地练手。
// util/module-info.java
module util {exports com.example.util;
}// app/module-info.java
module app {requires util;
}
以下是核心Java代码片段,展示如何在 util 模块中提供一个简单的工具类,以及在 app 模块中调用它。请关注关键的包名、类名以及方法调用。
// util/com/example/util/Util.java
package com.example.util;public class Util {public static String greet() {return "Hello from modular Java!";}
}// app/com/example/app/Main.java
package com.example.app;import com.example.util.Util;public class Main {public static void main(String[] args) {System.out.println(Util.greet());}
}运行前需要先把源代码编译并放置到module-path下,以确保模块在运行时能够正确定位。部署步骤包含:编译、打包、运行,其中运行时需要通过 --module-path 指定输出目录,确保模块路径正确解析。
# 假设当前在项目根目录,使用简单的目录结构
# 编译(按照实际目录结构执行相应命令)
javac -d out --module-source-path . $(find . -name "*.java")# 运行
java --module-path out -m app/com.example.app.Main4. 模块化的核心机制与声明方式
4.1 通过 module-info.java 声明依赖、暴露与服务
module-info.java是模块的核心描述文件,能够清晰地表达以下三类信息:exports用于暴露对外的包,requires用于声明对其他模块的依赖,opens用于打开运行时反射访问,常见于框架和服务提供者场景。
下面是一个更完整的示例,展示了如何在 util 模块中暴露接口和实现,并在 app 模块中通过 requires 进行依赖绑定,以及在运行时使用服务提供者 (Service Loader) 的基本思路。
// util/module-info.java
module util {exports com.example.util;exports com.example.util.spi; // 暴露给其他模块的服务接口requires transitive java.logging;
}// util/src/com/example/util/Greeter.java
package com.example.util.spi;public interface Greeter {String greet();
}// util/src/com/example/util/EnglishGreeter.java
package com.example.util;import com.example.util.spi.Greeter;public class EnglishGreeter implements Greeter {public String greet() { return "Hello!"; }
}// util/module-info.java (服务提供者声明)
module util {// 已在上方暴露的接口provides com.example.util.spi.Greeter with com.example.util.EnglishGreeter;
}
// app/module-info.java
module app {requires util;uses com.example.util.spi.Greeter;
}在应用层,通过 Service Loader 机制动态发现并使用实现类,这种模式在模块化架构中尤为常见,能够降低直接耦合、提高可扩展性。上述代码展示了最基本的服务暴露与使用路径,实际应用中可以结合日志、错误处理等机制来完善。
除了服务提供者,模块也支持对互相依赖的显式控制,例如:exports对外暴露的包范围、opens用于在运行时进行反射访问等。理解并灵活应用这些关键字,是成为模块化开发高手的关键一步。
5. 模块化项目的打包、执行与调试要点
5.1 运行时的模块路径与入口定位
在实际部署中,模块化项目的运行需要确保模块路径正确设置,主类所在的模块必须能够被运行时正确加载。常见的做法是把编译输出放到一个目录(如 out),再通过 --module-path 指定该目录,最后通过 -m 指定主模块与主类。
此外,调试阶段可利用 IDE 的模块化调试支持,设置运行配置时指定 module-path、module 与 主类,这样可以实现单步调试、断点定位与运行时日志分析等功能。
# 编译与打包(简化示例)
javac -d out --module-source-path . $(find . -name "*.java")# 运行时环境配置
java --module-path out -m app/com.example.app.Main通过本指南的步骤,你已经从零基础逐步掌握了Java模块化开发的核心要点:Jigsaw的作用、module-info.java的使用、以及简单的


