实践 Maven 2:参与多个项目构建
使用 Maven 2 构建和测试简单项目是很直接的。本部分用第二个例子来展示更现实也更为通用的多模块项目。
NumOps
的例子将在此处的第二个例子里得到扩展。添加一个新 SubOps
类来支持减法,添加一个新 MulOps
类来支持乘法。
但 Operation
接口和 AddOps
类现在己从 NumOps
项目中移走。相反,它们和新的 SubOps
和 MulOps
类一起放到了一个叫做 OpsImp
的新项目中。图 7 显示了 NumOps
和 OpsImp
项目间的这种关系:
在大型软件开发项目中,子项目和子模块之间常存在依赖性。您可以将这里的这项技术应用到有着多个相互依赖项的任何多模块 Maven 项目中。
清单 13 里的 SubOps
在编码上和 AddOps
类似。这里没有显示的 MulOps
也类似;您可以看一下随附的代码来了解详情(参见 下载)。
清单 13. 实现 Operation 接口的新 SubOps 类
package com.ibm.devworks; public class SubOps implements Operation { public int op(int a, int b) { return a-b; } public String getDesc() { return "minus"; } } |
现在修改了 NumOps
的构造函数来创建一个 SubOps
实例和一个 MulOps
实例。参见随附的源代码获取详情。
为和这两个项目一起运行,主项目创建在比 NumOps
和 OpsImp
的项目目录高一级的目录。NumOps
和 OpsImp
项目都使用标准 Maven 项目目录布局。在最顶部,项目目录只包含一个 pom.xml 文件。图 8 显示了新的子目录结构,紧跟在主目录之下:
可以在分发代码的 example2 子目录中找到这个多模块项目的代码(参见 下载)。清单 14 显示了顶层的 pom.xml 文件:
<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.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ibm.devworks</groupId> <artifactId>mavenex2</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <name>Maven Example 2</name> <url>http://maven.apache.org</url> <modules> <module>NumOps</module> <module>OpsImp</module> </modules> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> <dependencyManagement> <dependencies> <dependency> <groupId>com.ibm.devworks</groupId> <artifactId>OpsImp</artifactId> <version>${project.version}</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project> |
新代码以粗体突出显示。首先,这个主项目的工件 ID 是 mavenex2
,其打包类型是 pom
。这向 Maven 2 传递出这样的信号:这是一个多模块项目。
随后,<modules>
标记指定组成此项目的两个模块:NumOps
和 OpsImp
。
这个主项目的子模块能从这个 pom.xml 文件中继承属性。说得更具体一点,这些子模块都不需要将 JUnit 声明为一个依赖项,即使它们都包含单元测试。这是因为它们继承了顶层定义的 JUnit 依赖项。
<dependencyManagement>
标记不指定此模块依赖的依赖项。相反,它主要由子模块使用。子模块能指定 <dependencyManagement>
标记中任何条目的依赖项,而无需指定具体的版本号。当项目树更改依赖项的版本号时,这很有用,可以使需编辑的条目数目最小化。在本例中,OpsImp
项目的版本号是使用 ${project.version}
指定的。在执行 Maven 时,这是一个会被相应值所填充的参数。
前进到下一层的 OpsImp 目录,可以找到该模块的 pom.xml 文件,如清单 15 所示:
清单 15. 新 OpsImp 项目的 pom.xml 文件
<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.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <groupId>com.ibm.devworks</groupId> <artifactId>mavenex2</artifactId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>OpsImp</artifactId> <packaging>jar</packaging> </project> |
<parent>
元素指定此模块所继承自的主 POM。从父模块中继承极大地简化了这个 pom.xml。只需要覆盖该工件 ID 并打包。此模块继承了其父模块的依赖项:JUnit 模块。
NumOps
pom.xml 也从其父模块中继承,也相当简单。这个 pom.xml 显示在清单 16 中:
清单 16. NumOps 项目中显示 POM 继承关系的 pom.xml
<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.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <groupId>com.ibm.devworks</groupId> <artifactId>mavenex2</artifactId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>NumOps</artifactId> <packaging>jar</packaging> <dependencies> <dependency> <groupId>com.ibm.devworks</groupId> <artifactId>OpsImp</artifactId> </dependency> </dependencies> </project> |
NumOps
POM 中有意思的一处是将 OpsImp
项目指定为一个依赖项。请注意,在这个依赖项中没有指定任何版本号。在它的父项目的 <dependencyManagement>
元素里已经指定了首选的版本号。
在项目顶层,现在可以用 mvn compile
命令编译全部两个模块,或用 mvn test
命令为两个模块运行单元测试。也可以运行 mvn install
将打包的模块安装到本地目录中。这使得任何依赖于它的模块可以不访问源代码就能解析依赖项。