1. 概述
Java 平台模块系统(JPMS)从 Java 9 开始引入,为 Java 应用带来了更好的可靠性、更清晰的关注点分离以及更强的封装性。但 JPMS 本身不是一个构建工具,它不具备自动管理项目依赖的能力。
那我们自然会想:是否可以在模块化项目中继续使用 Maven 或 Gradle 这类成熟的构建工具?
答案是肯定的。本文将通过一个完整的示例,演示如何在 Maven 多模块项目中使用 Java 模块(Java Module),实现模块化与依赖管理的完美结合。
2. Maven 模块与 Java 模块的结合
Maven 的多模块项目通过 parent POM 定义多个子模块,并通过 reactor 机制控制构建顺序。而 Java 模块则通过 module-info.java
实现模块封装与依赖声明。
两者并不冲突,我们可以将每个 Maven 模块封装成一个 Java 模块,从而在享受 Maven 依赖管理的同时,获得模块化带来的封装性优势。
✅ 关键点:
- 每个 Maven 模块对应一个 Java 模块
- 使用
module-info.java
定义模块依赖和导出包 - Maven 负责构建顺序与依赖管理,Java 模块负责运行时隔离
3. 父级 Maven 模块配置
我们创建一个名为 multimodulemavenproject
的根目录作为项目基础结构。
父级 POM(pom.xml
)内容如下:
<groupId>com.baeldung.multimodulemavenproject</groupId>
<artifactId>multimodulemavenproject</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<name>multimodulemavenproject</name>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.12.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
⚠️ 注意:
- 使用 Java 17 需要 Maven ≥ 3.5.0
- maven-compiler-plugin ≥ 3.8.0 才支持 Java 17+
4. 子模块定义与封装
我们构建如下四个 Maven 子模块:
entitymodule
: 定义领域对象User
daomodule
: 定义 DAO 接口userdaomodule
: 实现 DAO 接口mainappmodule
: 主程序入口
4.1 entitymodule 模块
结构如下:
entitymodule
└── src
└── main
└── java
├── module-info.java
└── com
└── baeldung
└── entity
User.java
User.java
示例代码:
public class User {
private final String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "User{name='" + name + "'}";
}
}
module-info.java
:
module com.baeldung.entitymodule {
exports com.baeldung.entitymodule;
}
pom.xml
:
<parent>
<groupId>com.baeldung.multimodulemavenproject</groupId>
<artifactId>multimodulemavenproject</artifactId>
<version>1.0</version>
</parent>
<groupId>com.baeldung.entitymodule</groupId>
<artifactId>entitymodule</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>entitymodule</name>
父 POM 添加模块声明:
<modules>
<module>entitymodule</module>
</modules>
4.2 daomodule 模块
结构如下:
daomodule
└── src
└── main
└── java
├── module-info.java
└── com
└── baeldung
└── dao
Dao.java
Dao.java
示例代码:
import java.util.List;
import java.util.Optional;
public interface Dao<T> {
Optional<T> findById(int id);
List<T> findAll();
}
module-info.java
:
module com.baeldung.daomodule {
exports com.baeldung.daomodule;
}
pom.xml
:
<parent>
<!-- 父级坐标 -->
</parent>
<groupId>com.baeldung.daomodule</groupId>
<artifactId>daomodule</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>daomodule</name>
父 POM 添加模块声明:
<modules>
<module>entitymodule</module>
<module>daomodule</module>
</modules>
4.3 userdaomodule 模块
结构如下:
userdaomodule
└── src
└── main
└── java
├── module-info.java
└── com
└── baeldung
└── userdao
UserDao.java
UserDao.java
示例代码:
import java.util.*;
public class UserDao implements Dao<User> {
private final Map<Integer, User> users;
public UserDao(Map<Integer, User> users) {
this.users = users;
}
@Override
public Optional<User> findById(int id) {
return Optional.ofNullable(users.get(id));
}
@Override
public List<User> findAll() {
return new ArrayList<>(users.values());
}
}
module-info.java
:
module com.baeldung.userdaomodule {
requires com.baeldung.entitymodule;
requires com.baeldung.daomodule;
provides com.baeldung.daomodule.Dao with com.baeldung.userdaomodule.UserDao;
exports com.baeldung.userdaomodule;
}
pom.xml
:
<dependencies>
<dependency>
<groupId>com.baeldung.entitymodule</groupId>
<artifactId>entitymodule</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.baeldung.daomodule</groupId>
<artifactId>daomodule</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
父 POM 添加模块声明:
<modules>
<module>entitymodule</module>
<module>daomodule</module>
<module>userdaomodule</module>
</modules>
4.4 mainappmodule 模块
结构如下:
mainappmodule
└── src
└── main
└── java
├── module-info.java
└── com
└── baeldung
└── mainapp
Application.java
Application.java
示例代码:
import java.util.*;
import com.baeldung.dao.Dao;
import com.baeldung.userdao.UserDao;
import com.baeldung.entity.User;
public class Application {
public static void main(String[] args) {
Map<Integer, User> users = new HashMap<>();
users.put(1, new User("Julie"));
users.put(2, new User("David"));
Dao<User> userDao = new UserDao(users);
userDao.findAll().forEach(System.out::println);
}
}
module-info.java
:
module com.baeldung.mainappmodule {
requires com.baeldung.entitymodule;
requires com.baeldung.daomodule;
requires com.baeldung.userdaomodule;
uses com.baeldung.daomodule.Dao;
}
pom.xml
:
<dependencies>
<dependency>
<groupId>com.baeldung.entitymodule</groupId>
<artifactId>entitymodule</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.baeldung.daomodule</groupId>
<artifactId>daomodule</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.baeldung.userdaomodule</groupId>
<artifactId>userdaomodule</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
父 POM 添加模块声明:
<modules>
<module>entitymodule</module>
<module>daomodule</module>
<module>userdaomodule</module>
<module>mainappmodule</module>
</modules>
5. 项目结构总览
最终项目结构如下:
multimodulemavenproject
├── pom.xml
├── entitymodule
│ ├── pom.xml
│ └── src/main/java
│ ├── module-info.java
│ └── com/baeldung/entity/User.java
├── daomodule
│ ├── pom.xml
│ └── src/main/java
│ ├── module-info.java
│ └── com/baeldung/dao/Dao.java
├── userdaomodule
│ ├── pom.xml
│ └── src/main/java
│ ├── module-info.java
│ └── com/baeldung/userdao/UserDao.java
└── mainappmodule
├── pom.xml
└── src/main/java
├── module-info.java
└── com/baeldung/mainapp/Application.java
6. 运行应用
在命令行或 IDE 中运行 mainappmodule
模块,输出如下:
User{name='Julie'}
User{name='David'}
7. 小结
本文通过一个完整的 Maven 多模块项目,演示了如何结合 Java 模块系统(JPMS)进行开发。关键点总结如下:
✅ Maven 负责构建与依赖管理
✅ Java 模块提供运行时封装与模块化结构
✅ 每个 Maven 模块封装为一个 Java 模块,结构清晰、职责明确
✅ module-info.java
与 pom.xml
各司其职,互不干扰
如果你希望在大型项目中提升模块化程度与依赖管理能力,Maven + Java 模块是值得尝试的组合方案。
完整代码可在 GitHub 获取。