Maven聚合与继承

本文将在以下三部分进行编写:

  1. POM文件解析
  2. 构建顺序
  3. 可选择性部署

 Maven聚合即可以将多个子模块聚合在一起进行构建,继承即所有子模块均可以继承父模块的属性、依赖和插件等,可消除重复配置。

Maven基础性的知识不在此赘述,本文中涉及的Maven关键标签包括:

  • packaging:打包方式,常见的有jar(默认)、war和pom等;
  • module:子模块声明
  • properties:属性,可定义依赖报的版本号、定义某些插件的配置等;
  • dependencyManagement:依赖管理,具有依赖管理的POM,即不会给父模块引入依赖,也不会给子模块引入依赖。只有子模块声明依赖的使用(只需groupId和artifactId即可指明所用依赖),才会引入依赖包。使用import范围依赖导入依赖管理配置暂不讨论;
  • pluginManagement:插件管理,与依赖管理类似,该元素的配置不会实际插件调用的行为,只有当POM中正在配置对应的plugin元素才起作用;
  • repositories:用于声明远程仓库,可以是私有仓库(可由nexus搭建)。所有POM文件都会继承Maven顶级POM,其中包含Maven中央仓库。
  • distributionManagement:部署管理,可部署到远程Maven仓库,支持snapshotRepository和repository分别对应快照和稳定版本。

举一个比较常见的例子,假设某项目project包含三个模块,分别是:project_a、project_b、project_c,其文件结构如下,三个子模块与pom.xml在同一级,与父模块是父子目录结构:

/project
    /project_a
    /project_b
    /project_c
    pom.xml

1. POM文件解析

父模块project

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <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/xsd/maven-4.0.0.xsd">
 3   <modelVersion>4.0.0</modelVersion>
 4   <groupId>com.test</groupId>
 5   <artifactId>project</artifactId>
 6   <version>0.0.1-SNAPSHOT</version>
 7   <packaging>pom</packaging>
 8   <modules>
 9     <module>project_a</module>
10     <module>project_b</module>
11     <module>project_c</module>
12   </modules>
13   
14   <properties>
15       <spring.version>4.3.1.RELEASE</spring.version>
16   </properties>
17   
18   <dependencyManagement>
19       <dependencies>
20           <dependency>
21             <groupId>org.springframework</groupId>
22             <artifactId>spring-aop</artifactId>
23             <version>${spring.version}</version>
24         </dependency>
25         ......
26         <dependency>
27             <groupId>org.springframework</groupId>
28             <artifactId>spring-core</artifactId>
29             <version>${spring.version}</version>
30         </dependency>
31       </dependencies>
32   </dependencyManagement>
33   
34   <build>
35       <pluginManagement>
36           <plugins>
37               <plugin>
38                 <groupId>org.apache.maven.plugins</groupId>
39                 <artifactId>maven-compiler-plugin</artifactId>
40                 <version>3.1</version>
41                 <configuration>
42                     <source>1.7</source>
43                     <target>1.7</target>
44                 </configuration>
45             </plugin>
46               ......
47               <plugin>
48                 <groupId>org.apache.maven.plugins</groupId>
49                 <artifactId>maven-surefire-plugin</artifactId>
50                 <version>2.12.4</version>
51                 <configuration>
52                     <skipTests>true</skipTests>
53                 </configuration>
54             </plugin>
55           </plugins>
56       </pluginManagement>
57   </build>
58   
59   <repositories>
60         <repository>
61             <id>nexus</id>
62             <name>maven repository</name>
63             <url>http://serverip:port/nexus/content/groups/public/</url>
64             <snapshots>
65                 <enabled>true</enabled>
66             </snapshots>
67             <releases>
68                 <enabled>true</enabled>
69             </releases>
70         </repository>
71     </repositories>
72     
73     <!-- 发布 构件 到 私服 -->
74     <distributionManagement>
75         <repository>
76             <id>nexus</id>
77             <name>releases</name>
78             <url>http://serverip:port/nexus/content/repositories/releases/</url>
79         </repository>
80 
81         <snapshotRepository>
82             <id>nexus</id>
83             <name>snapshots</name>
84             <url>http://serverip:port/nexus/content/repositories/snapshots/</url>
85         </snapshotRepository>
86     </distributionManagement>
87 </project>
  •  4-6行:声明该构件在Maven仓库中的唯一坐标;
  • 7行: 打包方式为pom,起聚合作用的父模块必须声明为pom方式,否则构建失败;
  • 8-12行:聚合三个子模块project_a、project_b、project_c,每个module的值代表当前POM的相对目录,如果三个子模块与父模块是平行目录结构,则值应该为 ../project_a
  • 14-16行:定义POM属性,其可由子模块继承,在此声明为spring版本号;
  • 18-32行:配置依赖管理,对工程不会引入依赖,只有真正声明对应依赖才会引入;
  • 34-57行:配置插件管理,同依赖管理;
  • 59-71行:配置远程Maven仓库,需要在setting.xml中配置远程Maven仓库的用户名与密码等信息,如下:
<servers>
    <server>  
    <id>nexus</id>  
    <username>admin</username>  
    <password>admin123</password>  
    </server>  
</servers>
  •  74-86行:发布构件到私服配置,其他开发者可以使用该构件

子模块(project_a)

 1 <?xml version="1.0"?>
 2 <project
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
 4     xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 5     <modelVersion>4.0.0</modelVersion>
 6     <parent>
 7         <groupId>com.test</groupId>
 8         <artifactId>project</artifactId>
 9         <version>0.0.1-SNAPSHOT</version>
10     </parent>
11     <artifactId>project_a</artifactId>
12     <name>project_a</name>
13     
14     <dependencies>
15         <dependency>
16             <groupId>org.springframework</groupId>
17             <artifactId>spring-aop</artifactId>
18         </dependency>
19         ......
20         <dependency>
21             <groupId>org.springframework</groupId>
22             <artifactId>spring-core</artifactId>
23         </dependency>
24     </dependencies>
25     
26     <build>
27         <plugins>
28             <plugin>
29                 <groupId>org.apache.maven.plugins</groupId>
30                 <artifactId>maven-compiler-plugin</artifactId>
31             </plugin>
32               ......
33               <plugin>
34                 <groupId>org.apache.maven.plugins</groupId>
35                 <artifactId>maven-surefire-plugin</artifactId>
36             </plugin>
37         </plugins>
38     </build>
39 </project>
  •  6-10行:由parent元素声明该模块的父模块为project,其中省略了<relativePath>,该元素标识父模块POM的相对位置(由父模块与子模块的目录结构决定),默认值为 ../pom.xml,在本例子中为默认值;
  • 11-12行:由于继承了父模块中的所有配置,此处只需要声明artifactId即可,groupId与version继承自父模块。name元素用于描述,在构建日志找那个将显示该名;
  • 14-24行:真正声明所需依赖,会为该模块引入对应依赖,只需groupId和artifactId;
  • 26-38行:真正声明所需插件,也只需groupId和artifactId;

2. 构建顺序

在对工程只需 mvn clean install等命令的时候,Maven会首先解析聚合模块的POM、分析要构建的模块、并计算出一个反应堆构建顺序(Reactor Build Order),然后根据这个顺序依次构建模块。其中反应堆是所有模块组成的一个构建结构,包含各模块之间的继承与依赖关系,计算合理的模块构建顺序。(模块构建具体经历过哪些过程,可学习Maven中的生命周期)。

假设三个模块之间存在一定的依赖关系,如图:

本工程的构建顺序如下,聚合模块project、project_a、project_c、project_b:

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] project
[INFO] project_a
[INFO] project_c
[INFO] project_b
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------

 还可以通过命令行对反应堆进行裁剪,包括:

  • -am, --also-make 同时构建所列模块的依赖模块
  • -amd, --also-make-dependents 同时构建依赖于所列模块的模块
  • -pl, --projects <arg> 构建指定的模块,模块间用逗号分隔
  • -rf,-resume-form <arg> 从指定模块开始构建

举例:mvn clean install -pl project_a,project_b

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] project_a
[INFO] project_b
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------

 mvn clean install -pl project_a -am

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] project
[INFO] project_a
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------

 mvn clean install -pl project_a -amd

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] project_a
[INFO] project_c
[INFO] project_b
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------

 mvn clean install -pl project_a -amd -rf project_c

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] project_c
[INFO] project_b
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------

3. 可选择性部署

在父模块中声明了distributionManagement,在执行 mvn deploy的时候,会将所有的模块部署到远程服务器上。如何做到有选择性的的部署呢?比如不想将project_a部署到Maven仓库,有两种方式:

(1)在properties元素中声明 maven.deploy.skip

  在project_a模块的POM文件中添加如下配置:

<properties>
      <maven.deploy.skip>true</maven.deploy.skip>
</properties>

 (2)声明子模块插件,覆盖父模块插件

在project_a模块的POM文件中,添加属于自己的部署插件:

<plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-deploy-plugin</artifactId>
       <version>2.4</version>
       <configuration>
            <skip>true</skip>
       </configuration>
 </plugin>

注意: 在部署的时候,不想将父POM工程部署到远程仓库,此时怎么办?需要注意的是如果在父POM中声明跳过部署,则所有子POM工程继承该属性而跳过部署。解决方案:父POM声明跳过部署,子POM覆盖该属性,声明为false。

总结

  • POM的聚合与继承,前者方便快捷构建项目,后者可以消除重复配置;
  • 除了本文举的例子,可以在聚合模块任意文件夹什么父模块,只需要改变module和relativePath的相对路径即可;
  • 根据反应堆对各模块间依赖关系的计算,形成合理的构建顺序,并可以对构建顺序进行裁剪;
  • 可以通过插件属性配置,实现模块可选择的部署;

参考:

原文地址:https://www.cnblogs.com/shuimuzhushui/p/7822719.html