Maven構建多模組工程

weixin_34007291發表於2017-08-19

除非是簡單的工程專案,實際工作中碰到的大部分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>
3972716-265266a992f40c1d.png
圖片.png

這裡不需要定義version和scope,因為會自動從父工程中繼承而來。
相同的道理,可以使用這種方式管理maven的外掛,只需要使用pluginManagement元素,具體的使用方式與依賴的管理方式是一模一樣的。

相關文章