背景
本文是《Java 后端从小白到大神》修仙系列第二十篇
,正式进入Java后端
世界,本篇文章主要聊Java基础
。若想详细学习请点击首篇博文,我们开始把。
文章概览
- Java 9+ 模块化编程
Java 9+ 模块化编程(JPMS)
1. 模块化概念
Java 模块化是 Java 9 引入的核心特性(Project Jigsaw),旨在解决大型项目中代码依赖混乱、JAR 文件臃肿、类路径冲突等问题。模块化通过 module-info.java 文件定义模块的边界,明确以下内容:
- 模块名称:唯一标识模块,模块目录名必须与模块名完全一致
- 导出的包:允许其他模块访问的包(exports)
- 依赖的模块:声明需要哪些模块(requires)
- 开放反射的包:允许其他模块通过反射访问(opens)
- 提供的服务:声明服务提供者或消费者(uses/provides)
模块化的核心目标是 强封装性 和 显式依赖管理。
2. 模块化编程
1. 手动创建
1. 创建项目根目录结构
1
2
3
4
5
6
7
8
9
10
11
12
|
# 项目根目录(非模块化根,仅用于组织)
mkdir my-modular-project && cd my-modular-project
# 创建模块1:com.example.greeting
mkdir -p com.example.greeting/src/com/example/greeting
new-item com.example.greeting/module-info.java
new-item com.example.greeting/src/com/example/greeting/GreetingService.java
# 创建模块2:com.example.app
mkdir -p com.example.app/src/com/example/app
new-item com.example.app/module-info.java
new-item com.example.app/src/com/example/app/Main.java
|
2. 编写模块描述文件
1
2
3
4
5
6
7
8
9
|
// com.example.greeting/module-info.java
module com.example.greeting {
exports com.example.greeting;
}
// com.example.app/module-info.java
module com.example.app {
requires com.example.greeting;
}
|
3. 编写代码文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// com.example.greeting/src/com/example/greeting/GreetingService.java
package com.example.greeting;
public class GreetingService {
public static String greet(String name) {
return "Hello, " + name + "!";
}
}
// com.example.app/src/com/example/app/Main.java
package com.example.app;
import com.example.greeting.GreetingService;
public class Main {
public static void main(String[] args) {
System.out.println(GreetingService.greet("Java Modules"));
}
}
|
4. 编译与运行
1
2
3
4
5
6
7
8
|
# 编译所有模块
javac -d out \
--module-source-path ".;com.example.greeting/src;com.example.app/src" \
--module com.example.greeting,com.example.app
# 运行主模块
java --module-path out \
--module com.example.app/com.example.app.Main
|
2. 使用 Maven 创建(推荐生产环境)
1. 创建父项目(聚合模块)
1
2
3
4
5
|
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=my-modular-project \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
|
2. 修改父项目为 pom 类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<!-- my-modular-project/pom.xml -->
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-modular-project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging> <!-- 关键:父模块使用 "pom" 作为打包方式 -->
<modules>
<module>com.example.greeting</module> <!-- 先注释该行,子模块创建完毕再打开,否则报错 -->
<module>com.example.app</module> <!-- 先注释该行,子模块创建完毕再打开,否则报错 -->
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>com.example.greeting</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
|
3. 创建子模块
进入父项目根目录下,使用 Maven 生成子模块。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# 创建 greeting 模块
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=com.example.greeting \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
# 创建 app 模块
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=com.example.app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
|
修改子模块的 pom.xml 文件
子模块 APP POM文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>my-modular-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>com.example.app</artifactId>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>com.example.greeting</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 升级编译器插件版本并配置模块化参数 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>21</release> <!-- 使用 release 参数替代 source/target -->
<compilerArgs>
<!-- 关键修正:指向本地仓库的模块路径 -->
<arg>--module-path</arg>
<arg>
${settings.localRepository}/com/example/com.example.greeting/${project.version}</arg> <!-- 动态获取本地仓库路径(无需硬编码) -->
<arg>--add-modules</arg> <!-- 显式添加依赖模块到编译路径 -->
<arg>com.example.greeting</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
|
子模块 GREETING POM文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>my-modular-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>com.example.greeting</artifactId>
<dependencies>
<!-- 这里可以添加其他依赖 -->
</dependencies>
</project>
|
子模块的 类 文件
子模块 APP 类文件
1
2
3
4
5
|
com.example.app\src\main\java\module-info.java,路径位置
module com.example.app {
requires com.example.greeting;
}
|
1
2
3
4
5
6
7
8
9
10
|
package com.example.app;
import com.example.greeting.GreetingService;
public class Main {
public static void main(String[] args) {
GreetingService service = new GreetingService();
System.out.println(service.getGreeting());
}
}
|
子模块 GREETING 类文件
1
2
3
4
5
|
com.example.greeting\src\main\java\module-info.java,注路径位置
module com.example.greeting {
exports com.example.greeting;
}
|
1
2
3
4
5
6
7
|
package com.example.greeting;
public class GreetingService {
public String getGreeting() {
return "Hello, Maven Modules!";
}
}
|
4. 最终目录结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
my-modular-project/
├── pom.xml
├── com.example.greeting
│ ├── src
│ │ └── main
│ │ └── java
│ │ ├── com/example/greeting/GreetingService.java
│ │ └── module-info.java
│ └── pom.xml
└── com.example.app
├── src
│ └── main
│ └── java
│ ├── com/example/app/Main.java
│ └── module-info.java
└── pom.xml
|
5. 编译并运行
cd my-modular-project
mvn clean install
1
2
|
使用 mvn exec:java(推荐)
mvn exec:java -pl com.example.app -Dexec.mainClass=com.example.app.Main
|
- -pl com.example.app 只运行 com.example.app 这个模块。
- -Dexec.mainClass=com.example.app.Main 指定 Main 入口类。
1
2
3
|
使用 java --module-path 运行
java --module-path com.example.greeting/target/com.example.greeting-1.0-SNAPSHOT.jar;com.example.app/target/com.example.app-1.0-SNAPSHOT.jar \
--module com.example.app/com.example.app.Main
|
- –module-path 指定模块路径(包括 com.example.greeting 和 com.example.app)。
- –module com.example.app/com.example.app.Main 指定运行 Main 类。
那么正确运行后,输出应该是:
Hello, Modular Java!
总结
Java 9+ 模块化编程(JPMS) vs. Maven 多模块项目管理。Java 9+ 模块化 (JPMS),是语言层面的模块化系统(Java Platform Module System),强封装性、明确的模块依赖关系、解决 JAR 地狱,代码结构层面(编译和运行时生效)。Maven 多模块项目,是项目构建工具的模块化管理(依赖和构建流程控制),代码组织、依赖复用、多模块协同构建,项目工程化层面(构建时生效)。