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中声明了,也不会产生任何实际的效果。