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>

上面有一个特殊的地方就是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>

这个父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>

上面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>

最后,同样需要把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>

可继承的POM元素

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

依赖管理

当多有模块中有相同的依赖时,我们可以将这些依赖提取出来,统一在父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>

上面使用了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>

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

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

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

如果子模块不声明依赖的使用,即使该依赖已经在父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>

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

  • 另外,依赖范围有个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>

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

插件管理

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>

当子模块需要生成源码包的时候,只需要如下简单的配置,代码如下:

子模块声明使用了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.5</source>
                    <target>1.5</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>

accout-email和account-persist可以完全地移除关于maven-compiler-plugin和maven-resources-plugin的配置,但他们仍然能享受这这个插件的服务,前一插件开启了jdk1.5编译的支持,后一插件也会使用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>

可以看到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>

上面配置就将源码目录改为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>
<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>

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

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

<build>
    <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>

这里依次定义了项目的主输出目录,主代码输出目录,最终构件的名称格式、测试代码输出格式、主源码目录,脚本源码目录、测试源码目录、主资源目录和测试资源目录。这就是Maven项目结构的约定。

接着,超级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>

5、反应堆

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

例如修改account-aggregator的聚合配置:

<modules>
    <module>account-email</module>
    <module>account-persist</module>
    <module>account-parent</module>
</modules>

构建account-aggregator,会看到如下输出:

[INFO] -----------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] Account Aggregator
[INFO] Account Parent
[INFO] Account Email
[INFO] Account Persist
[INFO]
[INFO] -----------------------------------------

以上,构建顺序不一定是顺序去读取POM的顺序。当一个模块依赖于另外一个模块,Maven会先去构建被依赖模块,如果被依赖的模块还依赖其他模块,则进一步先构建依赖的依赖。

                                                                                          账户注册服务4个模块的反应堆

从上到下的箭头表示pom的读取次序,从右至左的箭头表示模块之间的继承或者依赖。模块间的依赖(泛指依赖或者继承)关系会将反应堆构成一个有向非循环图(Directed Acyclic Graph,DGA),各个模块是该图的节点,依赖关系构成有向边。这个图不允许出现循环,因此,当出现模块A依赖于B,而B又依赖于A的情况时,Maven就会报错。

裁剪反应堆

一般来说,用户会选择构建整个项目或者选择构建单个的模块,但有些时候,用户会想要仅仅构建完整反应堆中的某些个模块。换句话说,用户需要实时地剪裁反应堆。

Maven提供很多命令行选项支持裁剪反应堆,输入mvn -h可以看到这些选项:

  • -am, --also-make 同时构建所列模块的依赖模块
  • -amd -also-make-dependents 同时构建依赖于所列模块的模块
  • -pl,--project <arg> 构建指定的模块,模块间用逗号分隔
  • -rf -resume-from <arg> 从指定的模块回复反应堆

默认情况从account-aggregator执行mvn clean install会得到如下完整的反应堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Aggregator
[INFO]Account Parent
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

可以使用-pl选项指定构建某几个模块,如运行如下命令:

$ mvn clean install -pl account-email,account-persist

得到的反应堆为:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

使用-am选项可以同时构建所列模块的依赖模块,例如:

$ mvn clean install -pl account-email -am

由于account-email依赖于account-parent,因此会得到如下反应堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Parent
[INFO]Account Email
[INFO]
[INFO]-----------------------------------------------------

使用-amd选项可以同时构建依赖于所列模块的模块。例如:

$ mvn clean install -pl account-parent -amd

由于account-email和account-persist都赖于account-parent,因此会得到如下反应堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Parent
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

使用-rf选项可以在完整的反应堆构建顺序基础上指定从哪个模块开始构建。例如:

$mvn clean install -rf account-email

完整的反应堆构建顺序中,account-email位于第三,它之后只有account-persist因此会得到如下的剪裁反应堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

最后在-pl -am或者-pl -amd的基础上,还能应用-rf参数,以对裁剪后的反应堆再次剪裁,例如:

$ mvn clean install -pl account-parent -amd -rf account-email

该命令中的-pl和-amd参数会裁剪出一个account-parent、account-email和account-persist的反应堆,在此基础上,-rf参数指定从account-email参数构建。因此会得到如下的反应堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

在开发过程中,灵活应用上述四个参数,可以帮助我们跳过无须构建的模块,从而加速构建。在项目庞大、规模特别多的时候,这种效果就会异常明显。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章