# Maven 聚合与继承

# 1 聚合

Maven 聚合(或者称为多模块),是为了能够使用一条命令就构建多个模块,例如已经有两个模块,分别为 account-email,account-persist,我们需要创建一个额外的模块(假设名字为 account-aggregator,然后通过该模块,来构建整个项目的所有模块,accout-aggregator 本身作为一个 Maven 项目,它必须有自己的 POM,不过作为一个聚合项目,其 POM 又有特殊的地方,看下面的配置:

   <project	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>
    <artifact>account-aggregator</artifact>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Account Aggregator</name>
    <modules>
        <module>account-email</module>
        <module>account-persist</module>
    </modules>

  </project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

特殊的地方就是 packaging,其值为 pom,如果没有声明的话,默认为 jar,对于聚合模块来说,其打包方式必须为 pom,否则无法构建。

modules 里的每一个 module 都可以用来指定一个被聚合模块,这里每个 module 的值都是一个当前 pom 的相对位置,本例中 account-email、account-persist 位于 account-aggregator 目录下,当三个项目同级的时候,上面的两个 module 应该分别为../account-email 和../account-persist

# 2 继承

在构建多个模块的时候,往往会多有模块有相同的 groupId、version,或者有相同的依赖,例如:spring-core、spring-beans、spring-context 和 junit 等,或者有相同的组件配置,例如:maven-compiler-plugin 和 maven-resources-plugin 配置,在 Maven 中也有类似 Java 的继承机制,那就是 POM 的继承。

继承 POM 的用法:

面向对象设计中,程序员可以通过一种类的父子结构,在父类中声明一些字段和方法供子类继承,这样可以做到“一处声明、多处使用”,类似的我们需要创建 POM 的父子结构,然后在父 POM 中声明一些配置,供子 POM 继承。

下面声明一个父 POM,如下:

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:shemaLocation="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>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Account Parent</name>

</project>
1
2
3
4
5
6
7
8
9
10
11
12

这个父 POM 中,groupId 和 version 和其它模块一样,它的 packaging 为 pom,这一点和聚合模块一样,作为父模块的 POM,其打包类型也必须为 pom,由于父模块只是为了帮助消除配置的重复,因此它本身不包含除 POM 之外的项目文件,也就不需要 src/main/java 之类的文件夹了。

有了父模块,就需要其它模块来继承它。首先将 account-email 的 POM 修改如下:

account-email 继承 account-parent 的 POM

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:shemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">

<parent>
    <groupId>com.juvenxu.mvnbook.account<groupId>
    <artifactId>account-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <relativePath>../account-parent/pom.xml</relativePath>
</parent/>

<artifactId>account-email</artifactId>
<name>Account Email</name>

<dependencies>
    ....
</dependencies>
<build>
    <plugins>
        ....
    </plugins>
</build>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

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

上面 POM 没有为 account-email 声明 groupId,version,不过并不代表 account-email 没有 groupId 和 version,实际上,这个子模块隐式的从父模块继承了这两个元素,这也就消除了不必要的配置。上例中,父子模块使用了相同的 groupId 和 version,如果遇到子模块需要使用和父模块不一样的 groupId 或者 version 的情况,可以在子模块中显式声明。对于 artifactId 元素来说,子模块更应该显式声明,因为如果完全继承 groupId、artifactId、version,会造成坐标冲突;另一方面,即使使用不同的 groupId 或 version,同样的 artifactId 容易造成混淆。

account-persist 继承 account-parent 的 POM

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
xsi:shemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">

<parent>
    <groupId>com.juvenxu.mvnbook.account<groupId>
    <artifactId>account-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <relativePath>../account-parent/pom.xml</relativePath>
</parent>

<artifactId>account-persist</artifactId>
<name>Account Persist</name>

<dependencies>
    ....
</dependencies>
<build>
    <testResources>
        <testResource>
            <directory>src/test/resources</directory>
            <filtering>true</filtering>
        </testResource>
    </testResources>
    <plugins>
        ....
    </plugins>
</build>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

最后,同样需要把 account-parent 加入到聚合模块 accountp-aggregator 中,代码如下:

将 account-parent 加入到聚合模块


 <project
	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>
    <artifact>account-aggregator</artifact>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Account Aggregator</name>
    <modules>
        <module>account-email</module>
        <module>account-persist</module>
        <module>account-parent</module>
    </modules>
    </project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 2.1 可继承的 POM 元素:

groupId:项目组ID,项目坐标的核心元素
version:项目版本,项目坐标的核心元素
description:项目的描述信息
organnization:项目的组织信息
inceptionYear:项目的创始年份
url:项目的URL地址
developers:项目的开发者信息
contributors:项目的贡献者信息
distributionManagement:项目的部署配置
issueManagement:项目的缺陷跟踪系统信息
ciManagement:项目的集成信息
scm:项目的版本控制系统信息
mailingLists:项目的邮件列表信息
properties:自定义的Maven属性
dependencies:项目的依赖配置
dependencyManagement:项目的依赖管理配置
repositories:项目的仓库配置
build:包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等
reporting:包括项目的报告输出目录配置,报告插件配置等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 2.2 依赖管理

当多有模块中有相同的依赖时,我们可以将这些依赖提取出来,同时在父 POM 中声明,这样就可以简化子模块的配置了,但是这样还是存在问题,当想项目中加入一些,不需要这么多依赖的模块,如果让这个模块也依赖那些不需要的依赖,显然不合理。

Maven 提供的 dependentcyManagement 元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活度。

在 dependentcyManagement 元素下的依赖声明不会引入实际的依赖,不过他能够约束 denpendencies 下的依赖使用。对上面的 accoun-parent 进行改进,代码如下:


<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:shemaLocation="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>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Account Parent</name
<properties>
    <springframework.version>2.5.6</springframework.version>
    <junit.version>4.7</junit.version>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${springframework.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

上面使用了 dependencyManagement 声明的依赖既不会给 account-parent 引入依赖,也不会给它的子模块引入依赖,不过这段配置是会被继承的。

修改 account-email 的 POM 如下:

继承 dependencyManagement 的 account-email POM

<properties>
<javax.mail.version>1.4.1</javax.mail.version>
<greenmail.version>1.3.1b</greenmail.version>
</properties>

<dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.mail</groupId>
        <artifactId>mail</artifactId>
        <version>${javax.mail.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.icegreen</groupId>
        <artifactId>greenmail</artifactId>
        <version>${greenmail.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>
</dependencyManagement>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

子模块只需要配置简单的 groupId 和 artifactId 就能获得对应的依赖信息,从而引入正确的依赖。

这种依赖管理机制似乎不能减少太多的 POM 配置,但是其好处很大,原因在于在 POM 中使用 dependencyManagement 声明依赖能够统一规范项目中依赖的版本,当依赖的版本在父 POM 中声明之后,子模块在使用依赖的时候就无效声明版本,也就不会发生多个子模块使用依赖版本不一致的情况。这可以降低依赖冲突的几率。

# 2.2.1 子模块不声明依赖的使用:

如果子模块不声明依赖的使用,即使该依赖已经在父 POM 的 dependencyManagement 中声明了,也不会产生任何实际的效果,如 account-persist 的 POM。

<properties>
<dom4j.version>1.6.1</dom4j.version>
</properties>

<dependencies>
<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>dom4j.version</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
</dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

这里没有声明 spring-context-support,那么该依赖就不会被引入。这正是 dependencyManagement 的灵活性所在.

# 2.2.2 依赖范围---import 导入:

import 依赖范围只有在 dependencyManagement 下才有效果,使用该范围的依赖通常指向一个 POM,作用是将目标中的 dependencyManagement 配置导入到当前 POM 的 dependencyManagement 中配置。

除了复制配置或者继承这两种方式之外,还可以使用 import 范围依赖将这一配置导入。 使用 import 范围依赖导入依赖管理配置

<dependencyManagement>
<dependencies>
    <dependency>
        <groupId>com.juvenxu.mvnbook.account<groupId>
        <artifactId>account-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
</dependencies>
</dependencyManagement>
1
2
3
4
5
6
7
8
9
10
11

注意,上面代码中依赖的 type 为 pom,import 依赖范围由于其特殊性,一般都指向打包类型为 pom 的模块。如果有多个项目,他们使用的依赖版本都是一致的,则可以定义一个 dependencyManagement 专门管理依赖的 POM,然后在各个项目中导入这些依赖管理配置。

# 2.2.3 插件管理

Maven 提供了 dependencyManagement 元素帮忙管理依赖,类似地,Maven 也提供了 pluginManagement 元素帮忙管理插件。该元素中配置的依赖不会造成实际的插件调用行为,当 POM 中配置了真正的 plugin 元素,并且其 groupId 和 artifactId 与 pluginManagement 中配置的插件匹配时,pluginManagement 的配置才会影响实际的插件行为。

前面有如何通过组件去将 jar-no-fork 目标绑定到 verity 生命周期阶段,以生成项目源码包。如果一个项目中有很多子模块,并且需要这些模块的源码包,那么很显然,为所有模块重复类似的插件配置不是最好的办法,这时最好的办法是在父 POM 中使用 pluginManagement 配置插件,代码如下:

<build>
<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-source-plugin</artifactId>
            <version>2.1.1</version>
            <executions>
                <execution>
                    <id>attach-sources</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>jar-no-fork</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</pluginManagement>
</build>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

当子模块需要生成源码包的时候,只需要如下简单的配置,代码如下: 子模块声明使用了 maven-source-plugin 插件,同时又继承了父模块的 pluginManagement 配置,两者基于 groupId 和 artifactId 匹配合并。

有了 pluginManagement 元素,accout-email 和 accout-persist 的 POM 也能得以简化了他们都配置了 maven-compiler-plugin 和 maven-resources-plugin。可以将这两个插件的配置移到 account-parent 的 pluginManagement 元素中,代码如下:

<build>
<pluginMangement>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifact>maven-resources-plugin</artifact>
            <configuration>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</pluginMangement>
</build>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

accout-email 和 account-persist 可以完全地移除关于 maven-compiler-plugin 和 maven-resources-plugin 的配置,但他们仍然能享受这这个插件的服务,前一插件开启了 jdk1.8 编译的支持,后一插件也会使用 UTF-8 编码处理资源文件。这背后涉及了很多 Maven 机制,首先,内置的插件绑定关系将两个插件绑定到了 account-email 和 account-persist 生命周期上,其次,超级 POM 为这两个插件申明了版本;最后,account-parent 中的 pluginManagement 对这两个插件的行为进行了配置。

当项目中的多个模块有同样的插件配置时,应当将配置移到父 POM 的 pluginMangement 元素中。即使各个模块对于同一插件的具体配置不尽相同,也应当使用父 POM 的 pluginManagement 元素同意声明插件的版本。甚至可以要求将所有用到的插件的版本在父 POM 的 pluginManagement 中声明,子模块使用插件时不配置版本信息,这么做可以统一项目的插件版本,避免潜在的插件不一致或者不稳定的问题,也更易于维护。

# 3、聚合与继承的关系

多模块中的聚合与继承其实是两个概念,其目的是完全不同的,前者主要是为了方便快速构建项目,后者主要是为了消除重复配置。

对于聚合模块来说,它知道有哪些被聚合的模块,但那些被聚合的子模块不知道这个聚合模块的存在。

对于继承关系的父 POM 来说,它不知道哪些子模块继承于它,但那些子模块都必须知道自己的父 POM 是什么。

在现有的实际项目中,往往会发现一个 POM 即是聚合 POM,又是父 POM,这么做主要是为了方便。一般来说,融合使用聚合与继承也没什么问题,例如可以将 account-aggretor 和 account-parent 其 POM 如下:

<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>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Account Parent</name>
<modules>
    <module>account-persist</module>
</modules>
<properties>
    <springframework.version>2.5.6</springframework.version>
    <junit.version>4.7</junit.version>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${springframework.version}</version>
        </dependency>
       <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>junit<groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resource-plugin<artifactId>
                <configuration>
                    <endcoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

可以看到 POM 的打包方式为 pom,它包含了一个 modules 元素,表示用来聚合 account-persist 和 account-email 两个模块,它还包含了 properties、dependencyManagement 和 pluginManagement 元素供子模块继承。

# 4、约定优于配置

Maven 默认的源码目录是:src/main/java 但是用户也可以自己指定源码目录,如下:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juvenxu.mvnbook<groupId>
<artifactId>my-project</artifactId>
<version>1.0</version>
<build>
    <sourceDirectory>src/java</sourceDirectory>
</build>
</project>
1
2
3
4
5
6
7
8
9

上面配置就将源码目录改为 src/java 而不是默认的 src/main/java

任何一个 Maven 项目都隐式的继承自该 POM,这有点类似任何一个 Java 类都隐式的继承于 Object 类,因此,大量超级 POM 的配置都会被所有 Maven 项目继承,这些配置也就成为了 Maven 所提倡的约定。

对于 Maven3,超级 POM 在文件 MAVEN_HOME/lib/maven-model-builder-x.x.x.jar 中的 org/apache/maven/model/pom-4.0.0.xml 路径下。对于 Maven2,超级 POM 在文件 MAVEN_HOME/lib/maven-x.x.x-uber.jar 中的 org/apache/maven/project/pom-4.0.0.xml 目录下。

超级 POM 的内容在 Maven2 和 Maven3 中基本一致,分段看一下,见代码:

<repositories>
<repository>
    <id>central</id>
    <name>Maven Repository Switchboard</name>
    <url>http://repo1.maven.org/maven2</url>
    <layout>default</layout>
    <snapshots>
        <enabled>false</enabled>
    </snapshots>
</repository>
</repositories>
1
2
3
4
5
6
7
8
9
10
11
<pluginRepositories>
<pluginRepository>
    <id>central</id>
    <name>Maven Plugin Repository</name>
    <url>http://repo1.maven.org/maven2</url>
    <layout>default</layout>
    <snapshots>
        <enabled>false</enabled>
    </snapshots>
    <releases>
        <updatePolicy>never</updatePolicy>
    </releases>
</pluginRepository>
</pluginRepositories>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

超级 POM 定义了仓库及插件仓库,两者的地址都是为中央仓库http://repo1.maven.org/maven2,并且都关闭了SNAPSHOT的支持,这也就解释了为什么Maven默认就可以按需要从中央仓库下载构件。

超级 POM 中关于项目结构的定义:

这就是 Maven 项目结构的约定:

<directory>${project.basedir}/target<directory><!--主输出目录 -->
<outputDirectory>${project.build.directory}/classes</outputDirectory><!-- 主代码输出目录-->
<finalName>${project.artifactId}-${project.version}</finalName><!--最终构件的名称格式 -->
<testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory><!--测试代码输出格式 -->
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory><!-- 主源码目录-->
<scriptSourceDirectory>src/main/script</scriptSourceDirectory><!--脚本源码目录 -->
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory><!-- -->
<resources>
    <resource>
        <directory>${project.basedir}/src/main/resources</directory><!--测试源码目录 -->
    </resource>
</resources>
<testResources>
    <testResource>
       <directory>${project.basedir}/src/test/resources</directory><!-- 主资源目录和测试资源目录-->
    </testResource>
</testResources>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

接着,超级 POM 为核心差劲设定版本,代码如下:

<pluginManagement>
<plugins>
    <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.3</version>
    </plugin>

    <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2-bete-4</version>
    </plugin>

    <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>2.3</version>
    </plugin>

    <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
    </plugin>
    ........
</plugins>
</pluginManagement>

</build>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 5、反应堆

在一个多模块的 Maven 项目中,反应堆(Reactor)是指所有模块组成的一个构建结构。对于单模块的项目,反应堆就是该模块本身,对于多模块来说,反应堆就包含了各模块之间继承与依赖的关系,从而能够自动计算出合理的模块构建顺序。

例如:

<modules>
<module>account-email</module>
<module>account-persist</module>
<module>account-parent</module>
</modules>
1
2
3
4
5

以上,构建顺序不一定是顺序去读取 POM 的顺序,当一个模块依赖于另外一个模块,Maven 会先去构建被依赖模块,并且 Maven 中不允许出现循环依赖的情况,就是,当出现模块 A 依赖于 B,而 B 又依赖于 A 的情况时,Maven 就会报错。