深入解析Java模块系统:Root Modules与Java EE的融合之道
在Java 9中,模块系统引入了一种新的编程范式,使得代码的组织和依赖管理更加清晰。本文将详细探讨Root Modules的概念,以及如何在Java 9中继续使用Java EE库,例如JAXB。
Root Modules概述
Root Modules是JDK 9中引入的一个概念,它们只包含文件,不包含任何包或Java代码。这些模块的主要作用是依赖其他模块,并使它们对外可见。
就是这样一个模块,下面我们看看它的声明方式:
module java.se {
requires transitive java.compiler;
requires transitive java.datatransfer;
// 其他依赖省略...
}
- 1
- 2
- 3
- 4
- 5
'requires transitive’子句解析
transitive
关键字的效果是,目标模块不仅被当前模块(例如)所依赖,而且对依赖当前模块的其他模块也是可见的。例如
requires transitive
将使得对依赖
模块的模块可见。这与
exports
不同,exports
用于使包可见,而requires transitive
用于使导入的模块对外可见。
Root Modules的使用
当编译或加载未命名模块时,应该能够访问一组Root Modules中的一个,以便非模块化应用程序能够继续工作。默认的Root Modules集合是实现特定的。在JDK实现中,它是模块。如果我们使用一个不在默认Root Modules集合中的模块中的类会怎样呢?让我们通过一个例子来了解。
实例分析
以下示例使用JAXB API将字符串反序列化为对象:
public class MsgUnMarshaller {
public static void main(String... st) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(MsgObj.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader("<msgObj><msg>test msg</msg></msgObj>");
MsgObj msgObj = (MsgObj) unmarshaller.unmarshal(reader);
System.out.println(msgObj);
}
}
@XmlRootElement
public class MsgObj {
private String msg;
// getter和setter方法省略...
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
在尝试编译上述代码时,我们遇到了错误,因为JAXB相关的类对我们的未命名模块不可见。原因是中的默认Root Modules没有包含
requires transitive
。为了解决异常,我们需要使用--add-modules
来添加模块。
编译与运行
使用以下命令编译和运行程序:
javac --add-modules -d out src/com/logicbig/ src/com/logicbig/
java --add-modules -cp out
- 1
- 2
Java 9之前的情况
在Java 9之前,JAXB API和其他Java EE API自Java SE 6以来就捆绑在Java SE中,无需额外配置即可工作。Java 9决定通过新的模块系统将这些Java EE API从Java SE中分离出来,以减小JRE的大小,使其能够在更小的设备上运行。
模块
如果你的应用程序使用了大量的Java EE API,它在Java 9中运行时可能会失败。例如,如果你在应用程序中使用了JPA/Hibernate,它在编译和运行时可能会失败。与其逐个找出所需的模块,不如使用 module
中声明的Java SE和Java EE模块的混合集。我们可以通过--add-modules
选项启用这组Root Modules。
在IDE中设置–add-modules选项
所有IDE都有设置编译器和JVM运行时选项的功能。例如,在IntelliJ中,我们可以如下设置它们:
示例项目
使用的技术与依赖:
- JDK 9