Maven 聚合工程的創建

簡單場景舉例

image-20221103204530487

聚合工程創建示例

說明:

  • 創建 Maven Project:表示創建 maven 項目,new Project 方式創建
  • 創建 Maven Module:表示創建 maven 項目,new Module 方式創建
  • 創建 SpringBoot Module:表示創建 SpringBoot 項目,new Module 方式創建

注意:各個子工程的包名要保持一致

  1. 創建 Maven Project,命名 parent-project,刪除 src 目錄,pom 中添加 packing 標籤,指定打包類型為 pom,此項目作為父工程,不寫程式碼,做依賴管理。

  2. 在父工程 parent-project 下,創建 Maven Module,命名 common-project,此項目作為公共工程,寫那些可復用的程式碼功能,打包安裝後供其他子工程模組復用。

    說明:在公共工程中書寫程式碼後,使用側邊欄 maven 管理 Lifecycle 中 install 命令進行打包安裝,在其他子工程中直接添加該公共工程的依賴即可復用其中的程式碼功能。

  3. 在父工程 parent-project 下,創建 SpringBoot Module,命名 a-project,此項目作為子工程,寫功能程式碼,同時,可復用公共工程 common-project。(子模組 pom 中添加公共模組依賴坐標即可在工程中復用功能程式碼)

    說明:

    創建 SpringBoot 項目時,項目 pom 中可能會有指向 spring-boot-starter-parent 的父依賴存在,也可能沒有。

    詳細參考://blog.51cto.com/u_15692960/5405687

    子工程 pom 整理說明

    1. 如果創建的子工程有 parent 標籤且繼承的是 spring-boot-starter-parent,則直接將其剪切到父工程中;

      <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-parent</artifactId>
          <version>2.6.6</version>
      </parent>
      

      如果創建的子工程沒有 parent 標籤繼承的 spring-boot-starter-parent,則代表項目本身已做相關配置,不需要該父依賴,不需要做其他處理,此步驟忽略!

      注意:有無 parent 標籤可能是 SpringBoot 項目創建的方式不同(中國和國外方式)

    2. 將 common-project 中 parent 標籤(含父工程坐標)複製一份到本子工程中【也就是添加父依賴,繼承父工程】

    3. 刪除自己的 groupId 和 version

    4. 確保父工程 pom 的 modules 中有本子模組,沒有則手動添加

    5. 將子工程中公共的配置挪到父工程中,如需要交給父工程管理的依賴、一些 properties 以及 build 等公共配置

    PS:其他子工程如 b-project 和 c-project 的創建和整理步驟同 a-project。

  4. 以上,聚合工程創建完成。

以下展示聚合工程各工程模組中 pom 示例:

【實際開發,介面應用子工程創建一個 SpringBoot 項目即可,其他公共子工程皆使用 maven 創建】

目錄總覽:(實際開發應該是父工程下多個公共工程,一個應用介面啟動工程)

  • parent-project:父工程
  • common-project:公共工程
  • a-project:子工程 a
  • b-project:子工程 b
  • c-project:子工程 c

image-20221103215002709

parent-project 的 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 有教程有,有教程沒有,看是否能正常啟動再決定是否添加 -->
    <!--<parent>-->
    <!--    <groupId>org.springframework.boot</groupId>-->
    <!--    <artifactId>spring-boot-starter-parent</artifactId>-->
    <!--    <version>2.6.6</version>-->
    <!--</parent>-->

    <!-- 父工程坐標 -->
    <groupId>com.luis</groupId>
    <artifactId>parent-project</artifactId>
    <version>1.0.0</version>

    <!-- 必須 -->
    <packaging>pom</packaging>

    <!-- 子模組 -->
    <modules>
        <module>common-project</module>
        <module>a-project</module>
        <module>b-project</module>
        <module>c-project</module>
    </modules>

    <!-- 設置相關屬性 -->
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <!-- 公共依賴 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <!-- 依賴管理,配置對應 jar 包版本-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- 相關插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.luis.AProjectApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

common-project 的 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">

    <!-- 繼承父工程 -->
    <parent>
        <artifactId>parent-project</artifactId>
        <groupId>com.luis</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>common-project</artifactId>

</project>

a-project 的 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">

    <!-- 繼承父工程 -->
    <parent>
        <artifactId>parent-project</artifactId>
        <groupId>com.luis</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>a-project</artifactId>

    <dependencies>
        <!-- common-project 依賴-->
        <dependency>
            <groupId>com.luis</groupId>
            <artifactId>common-project</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>

</project>

b-project 的 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">

    <!-- 繼承父工程 -->
    <parent>
        <artifactId>parent-project</artifactId>
        <groupId>com.luis</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>b-project</artifactId>

    <dependencies>
        <!-- common-project 依賴-->
        <dependency>
            <groupId>com.luis</groupId>
            <artifactId>common-project</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>

</project>

c-project 的 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">

    <!-- 繼承父工程 -->
    <parent>
        <artifactId>parent-project</artifactId>
        <groupId>com.luis</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>c-project</artifactId>

    <dependencies>
        <!-- common-project 依賴-->
        <dependency>
            <groupId>com.luis</groupId>
            <artifactId>common-project</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>

</project>

其他說明

  • 注意:各個子工程的包名要保持一致

  • 在父工程 pom 的 dependencies 標籤中添加的依賴,在其所有子工程中都有,而且和父工程依賴的版本完全一致。

  • 在父工程 pom 的 dependencyManagement 標籤中添加的依賴,子工程中默認是沒有的。

    但是,如果子工程中需要使用,則直接在其 dependencies 標籤中添加即可,此時可不指定版本號,默認使用的是父類中指定的版本號。

    若子工程不想使用父類中指定的版本號,則自己需要明確指定所用依賴的版本號。

  • 父工程的標誌:pom 中存在 modules 和 packing 標籤,且 packaging 標籤中打包類型必須為 pom。

  • 子工程的標誌:pom 中 存在 parent 標籤,且標籤內坐標指向父工程。

dependencyManagement 和 dependencies 組件區別:

  • dependencyManagement 組件用來申明依賴,但不導入;dependencies 組件用於導入依賴
  • 子項目不會繼承 dependencyManagement 組件中聲明的依賴,但如果子項目想導入某個父 pom 中 dependencyManagement 中的依賴,只需要填寫 groupId 和 artifactId,不需要填寫版本號,maven 會自動去父 pom 的 dependencyManagement 中找對應的 version,包括scope、exclusions 等

附實際開發案例參考

聚合工程案例各模組草圖

fmmall 聚合工程項目各模組以及依賴管理一覽圖:

image-20221104190311474

項目模組目錄:

image-20221104194719091

模組說明

父工程模組:fmmal

子工程模組:common、beans、mapper、service、api

注意:以上所有工程模組,除 api 是創建的 SpringBoot 項目,其他模組都是創建的 maven 項目。

聚合工程中的子工程,除了介面工程(需要啟動運行)需要創建為 SpringBoot 工程外,其他工程一般創建為 maven 工程,為介面工程提供復用服務。(如 common、beans、mapper、service 等此類工程)

依賴配置說明

  1. 所有子工程都要求有的依賴:在父工程 pom 的 dependencies 公共依賴中添加
  2. 多個子工程需要相同的依賴:在父工程 pom 的 dependencyManagement 依賴管理中添加,然後在需要依賴的子工程中自行添加(不用指定版本號),讓父工程做統一的依賴版本管理
  3. 子工程單獨需要的依賴:則直接在其 pom 中自行添加即可

依賴傳遞:B 依賴 C,A 又依賴 B,則 A 也依賴 C。(C 有的,A 也會有)

關於聚合工程 install 問題

因為是聚合工程,所以一定存在工程之間互相依賴;而被依賴的工程通常是需要打包後才可供給其他工程使用的。

在開發環境中,雖然我們直接運行啟動類也可正常調用相關程式碼服務,但是我們一般會先將父工程 install一下,保證所有子工程都可正常打包後,再運行介面啟動類運行項目。

基於以上說明,如果父工程 install 出現問題,如提示「程式包xxx不存在,找不到符號」,可參考以下解決辦法:

原因分析:

項目 build 過程出現問題,個人估計一般這種情況就是依賴問題,pom.xml 中導入有問題,有可能是 springboot 自身的編譯插件 spring-boot-maven-plugin 導致的。

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

解決方案:

不要將此插件放到頂級父工程中,在需要打成可執行 jar 的地方添加就好,如果是需要被依賴的,就不要添加此插件!

分析:結合此聚合案例,我們需要將此插件放到 api 介面工程中,它不是頂級工程,它不需要被依賴,它需要打成可執行 jar!

install 相關,關於包明明存在,卻出現編譯錯誤:程式包不存在的問題,詳細可參考:點擊查看原博文

聚合工程各 pom.xml 示例

ffmall 父工程的 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 看情況添加 -->
    <!--<parent>-->
    <!--    <groupId>org.springframework.boot</groupId>-->
    <!--    <artifactId>spring-boot-starter-parent</artifactId>-->
    <!--    <version>2.6.6</version>-->
    <!--</parent>-->

    <!-- 父工程坐標 -->
    <groupId>com.luis</groupId>
    <artifactId>fmmall</artifactId>
    <version>2.0.1</version>

    <!-- 打包類型為pom,必須!-->
    <packaging>pom</packaging>

    <!-- 子模組 -->
    <modules>
        <module>common</module>
        <module>beans</module>
        <module>mapper</module>
        <module>service</module>
        <module>api</module>
    </modules>

    <!-- 設置相關屬性 -->
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <!-- 公共依賴 -->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--<dependency>-->
        <!--    <groupId>org.springframework.boot</groupId>-->
        <!--    <artifactId>spring-boot-starter-test</artifactId>-->
        <!--    <scope>test</scope>-->
        <!--    <exclusions>-->
        <!--        <exclusion>-->
        <!--            <groupId>org.junit.vintage</groupId>-->
        <!--            <artifactId>junit-vintage-engine</artifactId>-->
        <!--        </exclusion>-->
        <!--    </exclusions>-->
        <!--</dependency>-->
    </dependencies>

    <!-- 依賴管理,配置對應 jar 包版本-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!--不要將此插件放到頂級父工程中,在需要打成可執行jar的地方添加就好了,如果是需要被依賴的,就不要添加此插件-->
    <!--<build>-->
    <!--    <plugins>-->
    <!--        <plugin>-->
    <!--            <groupId>org.apache.maven.plugins</groupId>-->
    <!--            <artifactId>maven-compiler-plugin</artifactId>-->
    <!--            <version>3.8.1</version>-->
    <!--            <configuration>-->
    <!--                <source>1.8</source>-->
    <!--                <target>1.8</target>-->
    <!--                <encoding>UTF-8</encoding>-->
    <!--            </configuration>-->
    <!--        </plugin>-->
    <!--        <plugin>-->
    <!--            <groupId>org.springframework.boot</groupId>-->
    <!--            <artifactId>spring-boot-maven-plugin</artifactId>-->
    <!--            <version>2.3.7.RELEASE</version>-->
    <!--            <configuration>-->
    <!--                <mainClass>com.luis.fmmall.ApiApplication</mainClass>-->
    <!--            </configuration>-->
    <!--            <executions>-->
    <!--                <execution>-->
    <!--                    <id>repackage</id>-->
    <!--                    <goals>-->
    <!--                        <goal>repackage</goal>-->
    <!--                    </goals>-->
    <!--                </execution>-->
    <!--            </executions>-->
    <!--        </plugin>-->
    <!--    </plugins>-->
    <!--</build>-->

</project>
common 子工程的 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>fmmall</artifactId>
        <groupId>com.luis</groupId>
        <version>2.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>common</artifactId>
    <!-- 不指定默認也是 jar -->
    <packaging>jar</packaging>

</project>
beans 子工程的 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>fmmall</artifactId>
        <groupId>com.luis</groupId>
        <version>2.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>beans</artifactId>
    <!-- 不指定默認也是 jar -->
    <packaging>jar</packaging>

</project>
mapper 子工程的 pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>fmmall</artifactId>
        <groupId>com.luis</groupId>
        <version>2.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mapper</artifactId>
    <!-- 不指定默認也是 jar -->
    <!--<packaging>jar</packaging>-->

    <dependencies>
        <!-- beans -->
        <dependency>
            <groupId>com.luis</groupId>
            <artifactId>beans</artifactId>
            <version>2.0.1</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!-- mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!-- spring-boot-starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.4.4</version>
        </dependency>
        <!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.9</version>
        </dependency>
        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.4.4</version>
        </dependency>
        <!-- junit 單元測試-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
service 子工程的 pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>fmmall</artifactId>
        <groupId>com.luis</groupId>
        <version>2.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service</artifactId>
    <!-- 不指定默認也是 jar -->
    <!--<packaging>jar</packaging>-->

    <dependencies>
        <!-- mapper -->
        <dependency>
            <groupId>com.luis</groupId>
            <artifactId>mapper</artifactId>
            <version>2.0.1</version>
        </dependency>
        <!-- common 需要用到 vo,utils,封裝數據傳參到前端以及工具類 -->
        <dependency>
            <groupId>com.luis</groupId>
            <artifactId>common</artifactId>
            <version>2.0.1</version>
        </dependency>
    </dependencies>

</project>
api 子工程的 pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0
         //maven.apache.org/xsd/maven-4.0.0.xsd">

    <!-- 父工程資訊 -->
    <parent>
        <groupId>com.luis</groupId>
        <artifactId>fmmall</artifactId>
        <version>2.0.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>api</artifactId>

    <!-- 依賴配置 -->
    <dependencies>
        <!-- service -->
        <dependency>
            <groupId>com.luis</groupId>
            <artifactId>service</artifactId>
            <version>2.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <!--不要將此插件放到頂級父工程中,在需要打成可執行jar的地方添加就好了,如果是需要被依賴的,就不要添加此插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.luis.fmmall.ApiApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
Tags: