pom之间的关系主要用于pom文件的复用,我理解来看就是用于工程之间的调用或者共同组织成一个大的工程。

一、pom之间的关系

1)依赖关系:pom中的依赖关系列表(dependency list)

<dependencies>  
   <dependency>  
     <groupId>junit</groupId>  
     <artifactId>junit</artifactId>  
     <version>4.0</version>  
     <scope>test</scope>  
   </dependency>  
   ...
</dependencies>

2)继承关系

为了减少重复代码的编写,就需要创建pom的父子结构,然后在pom中声明一些配置供子pom继承,以实现 “一处声明,多处使用” 的目的。

可继承的pom元素如下:

<groupId>

项目组ID,项目坐标的核心元素

<version>

项目版本,项目坐标的核心因素

<description>

项目的描述信息

<organization>

项目的组织信息

<inceptionYear>

项目的创始年份

<url>

项目的URL地址

<developers>

项目的开发者信息

<contributors>

项目的贡献者信息

<distributionManagement>

项目的部署配置

<issueManagement>

项目的缺陷跟踪系统信息

<ciManagement>

项目的持续集成系统信息

<scm>

项目的版本控制系统西溪

<malilingLists>

项目的邮件列表信息

<properties>

自定义的Maven属性

<dependencies>

项目的依赖配置

<dependencyManagement>

项目的依赖管理配置

<repositories>

项目的仓库配置

<build>

包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等

<reporting>

包括项目的报告输出目录配置、报告插件配置等

举个栗子:

<--父pom-->
<?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.0 http://maven.apache.org/maven-v4_0_0.xsd">  
        <modelVersion>4.0.0</modelVersion>  
        <groupId>com.juvenxu.mvnbook.account</groupId>  
        <artifactId>parent</artifactId>  
        <version>1.0.0-SNAPSHOT</version>  
        <packaging>pom</packaging>  
        <name>Parent</name>     
</project>

现在让子模块继承parent:

<?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.0 http://maven.apache.org/maven-v4_0_0.xsd">  
        <modelVersion>4.0.0</modelVersion> 
        <parent>
            <groupId>com.juvenxu.mvnbook.account</groupId>  
            <artifactId>parent</artifactId>  
            <version>1.0.0-SNAPSHOT</version>  
            <relativePath>../parent/pom.xml</relativePath>  
        </parent> 
        <artifactId>rabbit-email</artifactId> 
        <name>Rabbit Email</name> 
        <dependencies>
                ...
        </dependencies>
        <build>
             <plugins>
                ...
             </plugins>
        </build>
        ...
</project>

parent下的子元素groupId、artifactId和version指定了父模块的坐标,这三个元素是必须的。元素relativePath表示父模块POM的相对路径。当项目构建时,Maven会首先根据relativePath检查父POM,如果找不到,再从本地仓库查找。relativePath的默认值是../pom.xml,也就是说,Maven默认父POM在上一层目录下。

该栗子中rabbit-email的pom并没有设置version,实际上这个子模块隐士的从父模块继承了这两个元素,如果子模块中遇到与父模块中不一样的version,这时应该在子模块显示声明。

3)聚合关系

现在把父模块加入到聚合模块aggregator中,如下:

<?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.0 http://maven.apache.org/maven-v4_0_0.xsd">  
        <modelVersion>4.0.0</modelVersion>  
        <groupId>com.juvenxu.mvnbook.account</groupId>  
        <artifactId>aggregator</artifactId>  
        <version>1.0.0-SNAPSHOT</version>  
        <packaging>pom</packaging>  
        <name>Aggregator</name>  
        <modules>
             <module>parent</module>    
             <module>rabbit-email</module> 
        <modules>     
</project>

此时的目录结构parent、rabbit-email在模块结构上是同一级目录的,aggregator为三个目录的父目录。

二、pom的依赖管理

dependencies是可以被继承的,这个时候为了优化配置,因此我们可以把公共的jar包放到父模块parent中,比如org.springframework:spring-core:2.5.6在子模块中都会用到,因此可以将这个依赖配置放到父模块中,子模块就能移除这些依赖从而简化配置。

这种做法是可行的,但是存在问题。因为所有的子模块都会继承以上父模块的依赖项,不管子模块是否真的需要此依赖项。这样相当于子模块失去了这些依赖项继承的选择权(无条件继承)。假设后面加了模块xxx与springframework没半毛钱关系,让它依赖spring的依赖项显然是不合理的。

为此maven提供了dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖的使用灵活性。在dependencyManagement元素下的依赖声明不会引入到实际的依赖,不过它能约束dependencies下的依赖使用。

<?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.0 http://maven.apache.org/maven-v4_0_0.xsd">  
        <modelVersion>4.0.0</modelVersion>  
        <groupId>com.juvenxu.mvnbook.account</groupId>  
        <artifactId>parent</artifactId>  
        <version>1.0.0-SNAPSHOT</version>  
        <packaging>pom</packaging>  
        <name>Parent</name> 
        <properties>
              <springframework.version>2.5.6</springframework.version>
        </properties>
        <dependencyManagement>
              <dependencies>
                     <dependency>
                          <groupId>org.springframework </groupId>
                          <artifactId>spring-core</artifactId>
                          <version>${springframework.version}</version>
                     </dependency>
                     ......
              </dependencies>
        </dependencyManagement>
</project>

这里使用了dependencyManagement声明的依赖既不会给parent引入依赖项,也不会给他的子模块引入依赖,不过这段配置会被继承。现在修改rabbit-email的pom文件如下:

<?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.0 http://maven.apache.org/maven-v4_0_0.xsd">  
        <modelVersion>4.0.0</modelVersion> 
        <parent>
            <groupId>com.juvenxu.mvnbook.account</groupId>  
            <artifactId>parent</artifactId>  
            <version>1.0.0-SNAPSHOT</version>  
            <relativePath>../parent/pom.xml</relativePath>  
        </parent> 
        <artifactId>rabbit-email</artifactId> 
        <name>Rabbit Email</name> 
        <dependencies>
            <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
            </dependency>
            ......
        </dependencies>
        <build>
            <plugins>
                ......
            </plugins>
        </build>
</project>

上面的配置较原来简单了一些,在rabbit-email中的dependencies中只配置了groupId和artifactId,省去了version,如果父模块配置了依赖的scope也是可以省略的。这些信息可以省略是因为rabbit-email继承了parent中的dependencyManagement配置,完整的依赖声明已经包含在父POM中了,子模块只需简单的配置groupId和artifactId,版本是父模块中version指定的版本。

使用这种以来管理机制虽然不能减少太多的配置项,但是经过别人实践后强烈推荐的方法。如果子模块不声明依赖的使用,即使该依赖已经在父POM文件dependencyManagement中声明了,也不会产生任何实际的效果。