14.6 编译及打包
你已经掌握了如何建立项目和声明模块,接下来学习如何使用像Maven这样的构建工具编译你的项目。本节假设你已经对Maven有一定的了解,它是Java生态圈里使用最广泛的构建工具之一。除了Maven之外,另一个同样很流行的构建工具是Gradle,如果你从未听说过,建议你抽时间了解一下。
构建的第一步,你需要为每一个模块创建一个pom.xml文件。实际上,每一个模块都需要能单独编译,这样其自身才能成为一个独立的项目。你还需要为所有模块的上层父项目创建一个pom.xml,用于协调整个项目的构建。这样一来,项目的整体结构就如下所示:
|─ pom.xml
|─ expenses.application
|─ pom.xml|─ src|─ main|─ java|─ module-info.java|─ com|─ example|─ expenses|─ application|─ ExpensesApplication.java
|─ expenses.readers
|─ pom.xml|─ src|─ main|─ java|─ module-info.java|─ com|─ example|─ expenses|─ readers|─ Reader.java|─ file|─ FileReader.java|─ http|─ HttpReader.java
请注意这三个新创建的pom.xml以及Maven项目的目录结构。项目的模块描述符(module-info.java)应置于src/main/java目录之中。Maven会设置javac,让其匹配对应模块的源码路径。
<?xml version="1.0" encoding="UTF-8"?><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.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>expenses.readers</artifactId><version>1.0</version><packaging>jar</packaging><parent><groupId>com.example</groupId><artifactId>expenses</artifactId><version>1.0</version></parent></project>
有一点非常重要,你需要在代码中显式地指定构建过程中使用的父模块。父模块在这个例子中是ID为expenses的构件。正如很快就能看到的例子所示,你需要在pom.xml中显式地定义父模块。
接下来,你需要指定模块expenses.application对应的pom.xml。这个文件与之前的那个pom.xml很类似,不过你还需要为其添加对expenses.readers项目的依赖,因为ExpensesApplication需要使用它提供的类和接口进行编译:
<?xml version="1.0" encoding="UTF-8"?><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.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>expenses.application</artifactId><version>1.0</version><packaging>jar</packaging><parent><groupId>com.example</groupId><artifactId>expenses</artifactId><version>1.0</version></parent><dependencies><dependency><groupId>com.example</groupId><artifactId>expenses.readers</artifactId><version>1.0</version></dependency></dependencies></project>
至此expenses.application和expenses.readers都有了各自的pom.xml,你可以着手建立指导构建流程的全局pom.xml了。Maven通过一个特殊的XML元素支持一个项目包含多个Maven模块的情况,这个定义了对应的子构件ID。下面是完整的定义,它包含了前面提到的两个子模块expenses.application和expenses.readers:
<?xml version="1.0" encoding="UTF-8"?><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.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>expenses</artifactId><packaging>pom</packaging><version>1.0</version><modules><module>expenses.application</module><module>expenses.readers</module></modules><build><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><source>9</source><target>9</target></configuration></plugin></plugins></pluginManagement></build></project>
恭喜你!现在可以执行mvn clean package为你项目中的模块生成JAR包了。运行这条命令会产生下面的文件:
./expenses.application/target/expenses.application-1.0.jar./expenses.readers/target/expenses.readers-1.0.jar
把这两个JAR文件添加到模块路径中,你就可以运行你的模块应用了,如下所示:
java --module-path \./expenses.application/target/expenses.application-1.0.jar:\./expenses.readers/target/expenses.readers-1.0.jar \--module \expenses.application/com.example.expenses.application.ExpensesApplication
至此,你已经学习并创建了模块,知道如何利用requires引用java.base。然而现实生产环境中,软件依赖更多的往往是外部的模块和库。如果遗留代码库没有使用module-info.java,又该如何处理呢?下一节会通过介绍自动模块(automatic module)来回答这些问题。
