🧩 Java 模块化详解

Java 模块化(Jigsaw 项目)是 Java 9 引入的重要特性,旨在解决 JAR 地狱类路径冲突 问题。本文将深入讲解模块化的核心概念、使用方法及实战技巧,助你掌握模块化开发的精髓! 🚀


一、模块化概述

1. 什么是模块化?

模块化是将代码划分为独立的、可重用的单元,每个模块包含:

  • 模块描述文件module-info.java
  • (包含类和接口)
  • 资源文件

2. 模块化的优势

  • 强封装性:模块可以明确声明导出哪些包,隐藏内部实现。
  • 依赖管理:显式声明模块间的依赖关系,避免冲突。
  • 性能优化:JVM 可以仅加载必要的模块,减少内存占用。

3. Jar Hell

  • jar文件无法控制别人访问其内部的public的类
  • 无法控制不同jar包中,相同的类名(包名+类名)
  • Java运行时,无法判定classpath路径上的jar中有多少个不同版本的文件。Java加载第一个符合名字的类
  • Java运行时,无法预判classpath路径上是否缺失了一些关键类

4. 模块化系统

  • 模块化必须遵循的三个原则
    • 强封装性:一个模块必须能够对其他模块隐藏其部分代码
    • 定义良好的接口:模块必须向其他模块公开定义良好且稳定的接口
    • 显式依赖:明确一个模块需要哪些模块的支持才能完成工作

5. Jigsaw 拼图


二、模块的创建与运行

1. 创建模块

项目结构

myapp/

├── src/

│ ├── com.greetings/

│ │ ├── module-info.java

│ │ └── com/

│ │ └── greetings/

│ │ └── Main.java

模块描述文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/com.greetings/module-info.java
module com.greetings { // 定义模块名称
requires java.base; // 依赖基础模块
exports com.greetings; // 导出包
}
主类代码
// src/com.greetings/com/greetings/Main.java
package com.greetings;

public class Main {
public static void main(String[] args) {
System.out.println("Hello, Modular Java!");
}
}

2. 编译与运行

编译模块

1
javac -d mods/com.greetings src/com.greetings/module-info.java src/com.greetings/com/greetings/Main.java

运行模块

1
2
bash
java --module-path mods -m com.greetings/com.greetings.Main

输出:

1
Hello, Modular Java!

三、模块信息文件详解

1. 模块声明

1
2
3
4
5
6
module com.greetings {
requires java.base; // 依赖基础模块
requires java.logging; // 依赖日志模块
exports com.greetings; // 导出包
exports com.greetings.internal to com.othermodule; // 限制导出范围
}

2. 常用指令

       指令                    描述

       requires             声明依赖的其他模块

       exports              导出包给其他模块使用

       opens                开放包以支持反射访问

       uses                   声明服务使用者

       provides            声明服务提供者


四、服务与模块化

1. 服务接口

1
2
3
4
5
6
// src/com.greetings/com/greetings/HelloService.java
package com.greetings;

public interface HelloService {
void sayHello();
}

2. 服务实现

1
2
3
4
5
6
7
8
9
// src/com.greetings/com/greetings/HelloServiceImpl.java
package com.greetings;

public class HelloServiceImpl implements HelloService {
@Override
public void sayHello() {
System.out.println("Hello from Service!");
}
}

3. 模块描述文件

1
2
3
4
5
6
// src/com.greetings/module-info.java
module com.greetings {
requires java.base;
exports com.greetings;
provides com.greetings.HelloService with com.greetings.HelloServiceImpl;
}

4. 服务加载

1
2
3
4
5
6
7
8
9
10
11
12
13
// src/com.greetings/com/greetings/Main.java
package com.greetings;

import java.util.ServiceLoader;

public class Main {
public static void main(String[] args) {
ServiceLoader<HelloService> services = ServiceLoader.load(HelloService.class);
for (HelloService service : services) {
service.sayHello();
}
}
}

输出:

1
Hello from Service!

五、模块化的应用

1. 模块化 JAR 文件

  • 打包模块
    1
    jar --create --file=mlib/com.greetings.jar --main-class=com.greetings.Main -C mods/com.greetings .
  • 运行模块化 JAR
    1
    java -p mlib -m com.greetings

2. 模块化与反射

  • 使用 opens 指令开放包:
1
2
3
module com.greetings {
opens com.greetings.internal; // 允许反射访问
}

3. 模块化与依赖注入

  • 结合 Spring 或 Guice 等框架,实现模块化的依赖注入。

六、模块化的最佳实践

1. 模块划分原则

  • 高内聚:每个模块应专注于单一功能。

  • 低耦合:模块间依赖应尽量简单明确。

  • 分层设计:将系统划分为核心模块、服务模块和应用模块。

2. 模块化开发工具

  • Maven:支持模块化项目的构建。

  • Gradle:提供模块化插件。

  • JLink:生成自定义的运行时镜像。


七、资源推荐

📚 推荐书籍

  • 《Java 模块化开发指南》

  • 《Java 9 模块化开发实战》

🔗 在线资源

💡 小贴士:

  • 使用 jdeps 工具分析模块依赖关系。

  • 通过 jlink 生成轻量化的运行时镜像。

  • 在大型项目中优先模块化核心组件。

  • 掌握模块化,让你的 Java 项目更清晰、更高效! 🎯