Osheep

时光不回头,当下最重要。

Maven构建多模块工程

除非是简单的工程项目,实际工作中碰到的大部分Maven工程都是多模块的,各个项目模块可以独立开发,其中某些模块又可能会使用到其他的一些模块的功能,如何利用maven来构建一个多模块的工程呢?
Maven提供了继承和聚合方式用以构建多模块工程,类似于Java中的继承和聚合的概念。

项目继承结构

项目继承可以实现在父工程中创建的pom文件内容的复用。子工程可以自动继承到父工程中的pom文件属性。
比如在父工程的pom文件中定义以下属性:

<groupId>com.packt.cookbook</groupId>
<artifactId>project-with-inheritance</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>

那么在子工程中添加parent定义:

<parent>
    <groupId>com.packt.cookbook</groupId>
    <artifactId>project-with-inheritance</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>child</artifactId>
<packaging>jar</packaging>
<name>Child Project</name>

有了以上的定义,我们就可以在子工程中使用父工程的pom文件中定义的properties和dependencies中的内容了。

NOTE:

  1. 父工程必须是pom类型的(packaging)
  2. 父工程完全不知道存在子工程,只有子工程中定义的parent元素可以指定父工程

一般而言父工程都在子工程的上一级目录中,如果父工程不在子工程的上一级目录中,子工程会继续往上在maven仓库中寻找是否有满足要求的父工程。如果需要自己指定父工程的位置,可以新增一个<relativePath>../parent/pom.xml</relativePath>的配置。

模块聚合结构

一个父工程可以拥有很多子工程,而父工程无法明确知道其子工程。使用模块聚合可以使得父工程明确管理其子工程,而子工程又可以成为一个个独立的存在,不必明确知道其父工程的存在。
如何在父工程中定义模块呢?只需要在父工程的pom文件中定义modules元素,为每个子模块新建一个module配置即可。

    <modules>
        <module>admin</module>
    </modules>

这种管理方式虽然简单,但是并不能继承父工程中定义好的properties和依赖,每个子模块都必须独立定义自己的依赖和属性,没有发挥maven项目管理的最大威力。

继承与聚合结合使用

如何让maven工程既有继承带来的便利性又有聚合带来的明确性呢?答案就是把这两种特性结合起来,即使用继承,又使用聚合。
例如,这里让admin模块继承maven项目,同时maven项目又使用modules元素来明确管理admin模块。

<?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>cc.adays</groupId>
    <artifactId>maven</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>cc.adays.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>


            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.9</version>
                <executions>
                    <execution>
                        <id>copy-dependency</id>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <modules>
        <module>admin</module>
    </modules>

</project>

在admin子模块的pom中定义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/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>maven</artifactId>
        <groupId>cc.adays</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>admin</artifactId>

</project>

通过这种方式,admin子元素就可以直接使用父工程中定义的依赖和属性,而父工程maven又可以明确管理其子元素,一举两得。

多模块工程的依赖管理

最后一个问题,虽然继承真心很好用,但是有时候子工程并不想拥有父工程的全部依赖,怎么办?此时就必须仰仗dependencyManagement了。通过在父工程中定义dependencyManagement,然后在子模块中选择性地使用父工程中已经定义好的依赖,就非常方便了。
举个栗子:

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.3.10.RELEASE</version>
            </dependency>

            <!-- https://mvnrepository.com/artifact/junit/junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
                <scope>test</scope>
            </dependency>

        </dependencies>
    </dependencyManagement>

这里在父工程中定义了两个依赖,一个是spring,一个是Junit,但是我们的子模块中只想使用junit,所以在子模块的pom文件中,定义:

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>
《Maven构建多模块工程》

图片.png

这里不需要定义version和scope,因为会自动从父工程中继承而来。
相同的道理,可以使用这种方式管理maven的插件,只需要使用pluginManagement元素,具体的使用方式与依赖的管理方式是一模一样的。

点赞