这是一个演示 Java 9 模块化编程逐步演进的示例程序。要成功执行,你需要按照模块化项目的结构来组织代码和编译运行。
项目结构与模块划分
整个程序涉及多个模块,其依赖关系如下:
| 模块名称 | 描述 | 依赖关系 | 关键导出/声明 |
|---|---|---|---|
| appfuncs | 核心数学函数模块 | 依赖 appsupport (Listing 9) |
导出 appfuncs.simplefuncs 包 |
| appsupport | 支持函数模块 | 无 | 导出 appsupport.supportfuncs 包 |
| appstart | 主应用程序模块 | 依赖 appfuncs, userfuncs (Listing 20) |
uses 服务接口 BinFuncProvider |
| userfuncs | 用户函数接口模块 | 无 | 导出 userfuncs.binaryfuncs 包 |
| userfuncsimp | 用户函数实现模块 | 依赖 userfuncs (Listing 18) |
provides 服务实现 AbsPlusProvider, AbsMinusProvider |
执行步骤
- 创建目录结构
按照模块名创建对应的目录,并将 .java 文件放入正确的包路径下。
bash
# 项目根目录 (例如:/java-module-demo)
├── appsupport
│ └── src
│ └── appsupport
│ ├── module-info.java # Listing 7的内容
│ └── appsupport
│ └── supportfuncs
│ └── SupportFuncs.java # Listing 6 的内容
├── appfuncs
│ └── src
│ └── appfuncs
│ ├── module-info.java # Listing 9 的内容 (最终版)
│ └── appfuncs
│ └── simplefuncs
│ └── SimpleMathFuncs.java # Listing 8 的内容 (最终版)
├── userfuncs
│ └── src
│ └── userfuncs
│ ├── module-info.java # Listing 17 的内容
│ └── userfuncs
│ └── binaryfuncs
│ ├── BinaryFunc.java # Listing 11的内容
│ └── BinFuncProvider.java # Listing 12 的内容
├── userfuncsimp
│ └── src
│ └── userfuncsimp
│ ├── module-info.java # Listing 18 的内容
│ └── userfuncsimp
│ └── binaryfuncsimp
│ ├── AbsPlus.java # Listing 13 的内容
│ ├── AbsMinus.java # Listing 14 的内容
│ ├── AbsPlusProvider.java # Listing 15 的内容
│ └── AbsMinusProvider.java # Listing 16 的内容└── appstart └── src └── appstart
├── module-info.java # Listing 20 的内容 (最终版)
└── appstart
└── mymodappdemo └── MyModAppDemo.java # Listing 19 的内容 (最终版)
- 编译模块
必须按照模块间的依赖顺序进行编译。先编译被依赖的模块。
bash
# 在项目根目录下执行
# 1. 编译 appsupport模块
javac -d out/appsupport \
appsupport/src/appsupport/module-info.java \
appsupport/src/appsupport/appsupport/supportfuncs/SupportFuncs.java
# 2. 编译 userfuncs 模块
javac -d out/userfuncs \
userfuncs/src/userfuncs/module-info.java \
userfuncs/src/userfuncs/userfuncs/binaryfuncs/*.java
# 3. 编译 userfuncsimp 模块 (依赖 userfuncs)
javac --module-path out -d out/userfuncsimp \
userfuncsimp/src/userfuncsimp/module-info.java \
userfuncsimp/src/userfuncsimp/userfuncsimp/binaryfuncsimp/*.java
# 4. 编译 appfuncs 模块 (依赖 appsupport)
javac --module-path out -d out/appfuncs \
appfuncs/src/appfuncs/module-info.java \
appfuncs/src/appfuncs/appfuncs/simplefuncs/SimpleMathFuncs.java
# 5. 编译 appstart 模块 (依赖 appfuncs, userfuncs)
javac --module-path out -d out/appstart \
appstart/src/appstart/module-info.java \
appstart/src/appstart/appstart/mymodappdemo/MyModAppDemo.java
- 运行程序
使用 java 命令并指定模块路径和主模块/主类 。
bash
java --module-path out -m appstart/appstart.mymodappdemo.MyModAppDemo
- 预期输出
如果一切配置正确,程序将输出以下结果:
2 is a factor of 10
Smallest factor common to both 35 and 105 is 5
Largest factor common to both 35 and 105 is 7
Result of absPlus function: 16
Result of absMinus function: 8
核心概念解析
- 模块声明 (
module-info.java) :每个模块的根目录下必须有此文件,用于定义模块名、依赖 (requires)、导出包 (exports) 和服务声明 (provides...with/uses) 。 - 封装性 :未被
exports的包在模块外不可见,增强了代码的封装性和安全性 。 - 服务与提供者 :这是 Java 模块化中的高级特性。
userfuncs模块定义了服务接口 (BinaryFunc,BinFuncProvider),userfuncsimp模块提供了具体实现,appstart模块通过ServiceLoader动态发现和使用这些服务,实现了松耦合 。 - 传递依赖 (
requires transitive) :在appfuncs的模块声明中,requires transitive appsupport;使得依赖appfuncs的模块(如appstart)也能自动访问appsupport模块的内容,无需再次声明 。