Skip to content

Maven多模块构建机制

参考: https://www.iteye.com/blog/elim-2055745

maven基础回顾

maven通过groupdId:artifactId:version三者来唯一确定一个项目, 因此在pom.xml文件中这三者是必须配置的

json
<groupId>org.example</groupId>
<artifactId>demo-web</artifactId>
<version>1.0-SNAPSHOT</version>

maven命令

参考: https://blog.csdn.net/shenzhou_yh/article/details/105988113

json
常见参数
-D D代表Property属性 定义一个property, 示例$mvn clean package -Dmaven.test.skip=true
-P P代表Profile, 激活指定的profile文件列表, 以逗号隔开, 示例$mvn clean package -P prod
-f 使用指定的pom文件替换当前的pom文件
-ff 最快失败模式, 多模块构建时, 遇到第一个失败的构建时停止
-e 显示详细错误信息

-am 构建指定模块, 同时构建指定模块依赖的其他模块
-amd 构建指定模块, 同时构建依赖于指定模块的其他模块
-pl 手动选择要构建的项目, 项目间以逗号隔开

maven中的属性

在pom.xml中可以使用${propertyName}来引用属性, propertyName有以下几种形式:

- env.propertyName:环境变量,比如当前系统的环境变量${env.PATH}。
- project.propertyName:当前这个pom.xml中project根元素下面的子元素的值。比如${project.version}。
- settings.propertyName:Maven本地配置文件settings.xml或本地Maven安装目录下的settings.xml文件根元素settings下的元素。比如${settings.localRepository}
-  java的系统属性,所有在java中使用java.lang.System.getProperties()能够获取到的属性都可以在pom.xml中引用,比如${java.home}。
- pom.xml中properties元素下面的子元素作为属性。假如在pom.xml中有如下一段代码<properties><hello.world>helloWorld</hello.world></properties>,那么我们就可以使用${hello.world}引用到对应的helloWorld。

资源文件的打包

maven允许资源文件中的值在编译时动态指定, 建立文件时以${propertyName}的形式指定. maven这种动态替换属性值的功能默认是关闭的,如果要打开的话需要在项目的pom.xml文件中指定filtering的值为true,默认是false

示例场景: 当项目资源路径下有excel等模板文件时, 若开启了filter后, 打包会将模板文件中的${变量}替换掉, 影响模板的正常功能, 因此需要配置将相关文件的filter设为false

json
 <build>
        <resources>
						<resource>
                <directory>src/main/resources</directory>
                <targetPath>${dist.path}</targetPath>
                <filtering>true</filtering>
            </resource>

            <resource>
                <directory>src/main/resources</directory>
                <targetPath>${dist.path}</targetPath>
                <filtering>false</filtering>
                <includes>
                    <include>excel/**</include>
                    <include>es/**</include>
                </includes>
            </resource>
        </resources>
 </build>

多模块之间的关系

继承

形成继承关系需要在子项目pom.xml中定义指向父项目parent标签

继承的作用:

和java里面的继承类似,子pom.xml会完全继承父pom.xml中所有的元素,而且对于相同的元素,一般子pom.xml中的会覆盖父pom.xml中的元素,但是有几个特殊的元素它们会进行合并而不是覆盖。这些特殊的元素是:

  • dependencies
  • developers
  • contributors
  • plugin列表,包括plugin下面的reports
  • resources
json
示例: 工程结构如下, B在A项目目录下
projectA
--projectB
-------------projectB的pom.xml---------------
<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>projectA</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>projectB</artifactId>

</project>

注意: 若A与B在同级目录, 须通过relativePath指定父工程的pom.xml位置, relativePath指的是目录路径
--projectA
--projectB
-------------projectB的pom.xml---------------
<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>projectA</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
				<relativePath>../projectA/pom.xml</relativePath> 
    </parent>
    <artifactId>projectB</artifactId>

</project>

聚合

示例: 工程结构如下, B在A项目目录下

projectA

--projectB

如示例的工程结构, B项目聚合到A项目, 可以说B是A的子模块, A是被聚合的项目, 也是聚合的主体

形成聚合关系需要:

  1. 修改被聚合项目的pom.xml中的packaging元素的值为pom
  2. 主体项目pom.xml中定义聚合项目module

聚合的作用:

在主体项目目录下使用maven命令时, 这些命令都会在聚合项目下执行.

json
示例: 工程结构如下, B在A项目目录下
projectA
--projectB
-------------projectA的pom.xml---------------
<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>projectA</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>projectB</module>
    </modules>

注意: 若A与B在同级目录, 须在module中指定正确的目录路径
--projectA
--projectB
-------------projectA的pom.xml---------------
<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

     <groupId>org.example</groupId>
    <artifactId>projectA</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>../projectB</module>
    </modules>

</project>
Reactor

参考: https://blog.csdn.net/weixin_30408309/article/details/94972603

对于多模块的项目, maven的Reactor包含了各模块之间继承与依赖的关系, 从而能自动计算出合理的模块构建顺序.

  • 当需要构建整个项目时, 直接在项目目录下执行maven命令
  • 当只需要构建某个模块时, 就需要对反应堆进行裁剪
json
示例: 以下命令表示构建模块A并且构建A依赖的其他模块
mvn clean package -Dmaven.test.skip=true -pl moduleA -am

依赖

json
<dependency>
  <groupId>xxx</groupId>
  <artifactId>xxx</artifactId>
  <version>xxx</version>
  <type>jar</type> // 依赖项目的打包类型, 默认jar
  <scope>compile</scope> 

// 表示依赖项目的作用范围:
- compile, 默认值, 表示所有情况有效, 且可传递
- provided, 测试和编译有效, 运行时将有jdk或容器提供, 不可传递
- runtime, 运行时必须
- test, 测试时必须
- system, 类似provided, 结合systemPath使用

  <systemPath></systemPath> // 指定依赖的jar包在系统的绝对路径, 只在scope为system时才可以使用
  <optional></optional> // 可选的
  <exclusions> // 排除依赖
    <exclusion>
    	<artifactId></artifactId>
    	<groupId></groupId>
  	</exclusion>
  </exclusions>
</dependency>

补充: 只能有一个父工程, 其他依赖可以通过import方式导入

json
 <!--springboot-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.1.3.RELEASE</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>

多模块聚合工程的构建

由上面的总结, 一般多模块项目都会定义成父子以及聚合结构, 其中

  • 父子结构: 父pom.xml中统一定义依赖版本以及插件版本, 子工程无需对版本进行管理
  • 聚合结构: 用于构建项目时, 子工程一并构建, 但此时若要单独构建子工程, 则需要配合-pl am命令食用
json
示例项目结构:
demo-cloud
--demo-common // 定义通用实体
--demo-web // 定义web接口, 依赖于demo-common

demo-cloud父工程的pom.xml

xml
<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>demo-cloud</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>demo-web</module>
        <module>demo-common</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <dist.path>${basedir}/../target</dist.path>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.version>1.0-SNAPSHOT</project.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.example</groupId>
                <artifactId>demo-common</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.example</groupId>
                <artifactId>demo-web</artifactId>
                <version>${project.version}</version>
            </dependency>


            <!--springboot-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--fastjson-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.33</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

  <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>2.1.3.RELEASE</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

demo-web工程的pom.xml

xml
<?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/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>demo-cloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>demo-web</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>demo-common</artifactId>
        </dependency>

        <!--springbootTest-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

demo-common工程的pom.xml

xml
<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>demo-cloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>demo-common</artifactId>
</project>

此时若要单独构建demo-web(以及需要将依赖的demo-common打包进来), 在demo-cloud目录下命令如下

json
\demo-cloud> $mvn clean package -Dmaven.test.skip=true -pl ./demo-web -am