Maven多模塊項目與分析


為什么要用Maven多模塊

假設有這樣一個項目,很常見的Java Web應用。在這個應用中,我們分了幾層:
Dao
Service
Controller
對應的,在一個項目中,我們會看到一些包名:

org.xx.app.dao
org.xx.app.service
org.xx.app.web
org.xx.app.util

但隨着項目的進行,你可能會遇到如下問題:

  1. 這個應用可能需要有一個前台和一個后台管理端,你發現大部分dao,一些service,和大部分util是在兩個應用中可。
  2. pom.xml中的依賴列表越來越長以重用的,但是,由於目前只有一個項目,你不得不新建一個項目依賴這個WAR.
  3. build整個項目的時間越來越長,盡管你只是一直在web層工作,但你不得不build整個項目。
  4. 某個模塊,比如util,你只想讓一些經驗豐富的人來維護,可是,現在這種情況,每個開發者都能修改,這導致關鍵模塊的代碼質量不能達到你的要求。

我們會發現,其實這里實際上沒有遵守一個設計模式原則:“高內聚,低耦合”。雖然我們通過包名划分了層次,並且你還會說,這些包的依賴都是單向的,沒有包的環依賴。這很好,但還不夠,因為就構建層次來說,所有東西都被耦合在一起了。因此我們需要使用Maven划分模塊。
其實說白了,Maven多模塊就是為了更好的復用,所以,要求划分子模塊,為啥不單獨開工程,然后我們各自去引用呢?我認為有一下幾點:

  1. 每個工程單獨管理,必然要開單獨的倉庫,是否能及時更新,及時響應,不好管理;
  2. 每個單獨的工程,那就要單端部署和管理,如何部署,是否在同一台服務器上,是否支持遠程調用,增加了運營運維的成本,不好管理;
  3. 如果每個都單獨開工程,那么有一部分的基礎代碼就會重復,比如POJO,各種配置,這些就會冗余。
    所以,為了內聚和簡單可以重復使用這個因素,就直接在一個大的工程里面,直接去開辟小的模塊,這樣就避免了上述的3個問題。

Maven子模塊和父模塊的設置

在有子模塊的maven工程之中,有子模塊和父模塊兩個角色,父模塊是root的角色,一般我們在父模塊之中不寫代碼,所以創建好父模塊的工程之后,就會刪除src文件夾,父模塊其實就是起一個管理的作用,管理插件,管理依賴,保證我們的子模塊工程,使用的jar包在版本上是沒有沖突的,而真正實現功能的部分是在子模塊,子模塊之間就能夠相互引用(單方面的),這就是基本的一個思想,按照這個想法,我們所要做的事情,其實已經一目了然,父模塊-管理,子模塊->干活,父子之間有層級關系。我們使用的是Maven管理,那就必然是關系到pom.xml文件,其中就牽扯到parent,packaging,modules,dependencyManagement,pluginManagement。

  • parent
    • 所有的工程,都不需要寫parent了,父工程可以寫,但是沒必要,子模塊,沒法寫,因為父工程只是一個殼子,沒有包名,所以子模塊父模塊都不需要寫了,SpringBoot工程默認會有spring-boot-starter-parent的parent,可以直接去掉。
  • packaging
    • 父工程變為pom, 子工程變成jar或者war,按照需求,一般是jar,方便引入使用。
  • modules
    • 父工程之中使用modules標簽,一個工程一個module,把子工程包裹起來。
  • dependencyManagement
    • 父工程之中使用,依賴管理,相當於一個版本的定義,子工程可以不去使用,使用自己的版本也是可以的。
  • pluginManagement
    • 父工程之中使用,插件管理,相當於一個版本的定義,子工程可以不去使用,使用自己的版本也是可以的。

按照這個操作后,項目的關系在IDEA之中的顯示是如左圖圖的,也就是,在父工程后面,會標注一個root,而右邊的圖,bootvue雖然在springboot2.x-integration的文件夾下面,但是沒有父子關系的。下面展示三個pom配置:

zgytest的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!-- 父模塊,parent可有可無 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zgy.test</groupId>
    <artifactId>zgytest</artifactId>
    <packaging>pom</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>zgytest</name>
    <description>Demo project for Spring Boot</description>

    <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.0.RELEASE</spring-boot.version>
    </properties>

    <!-- 子模塊 -->
    <modules>
        <module>mine</module>
        <module>hello</module>
    </modules>

    <!-- 依賴管理 -->
    <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>

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

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <build>
        <!-- 插件管理 -->
        <pluginManagement>
            <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>
            </plugins>
        </pluginManagement>
    </build>

</project>

hello的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example.hello</groupId>
    <artifactId>hello</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>hello</name>
    <packaging>jar</packaging>
    <description>Demo project for Spring Boot</description>

    <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.0.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.taobao.arthas</groupId>
            <artifactId>arthas-spring-boot-starter</artifactId>
            <version>3.3.7</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <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>
        </plugins>
    </build>

</project>

mine的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example.dream</groupId>
    <artifactId>mine</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mine</name>
    <packaging>jar</packaging>
    <description>Demo project for Spring Boot</description>

    <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.0.RELEASE</spring-boot.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>


        <!-- 引入hello模塊 -->
        <dependency>
            <groupId>com.example.hello</groupId>
            <artifactId>hello</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

    </dependencies>

    <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>

        </plugins>
    </build>

</project>

Maven多模塊項目的創建

和普通的項目創建沒有區別,一般我們直接創建SpringBoot工程或者maven工程,按照上面的Maven子模塊和父模塊的設置的設置配置即可,關鍵點就是pom文件之中的parent,packaging,modules,dependencyManagement,pluginManagement這幾個標簽,其中parent,packaging,modules是必須處理的。詳細:Maven 多模塊父子工程 (含Spring Boot示例)https://www.cnblogs.com/flywang/p/8567175.html,https://blog.csdn.net/u013983628/article/details/89511553,https://blog.csdn.net/qq_42449963/article/details/105405247

Maven子模塊相互調用

其實,maven工程如果分成了子模塊父模塊的模式,父模塊只是一個殼子,相當於是進行了一個依賴,版本等的管理,更像是一個管家,而各個子模塊可以直接從父模塊獲取需要的依賴,這樣的話,就可以保證各個子模塊所獲取的依賴,沒有沖突,相同的依賴,不至於因為版本的不同而導致一些莫名其妙的問題發生,我們也知道,如果是子模塊之間,有依賴,那么我們就直接調用引入依賴即可,但是要確保這個時候是單向的,也就是要排除循環依賴的問題。比如,moduleA,moduleB,在moduleB之中依賴了moduleA,那么也就是要引入moduleA即可,如同下圖之中的mine工程,引入了hello模塊,和我們正常引入其他的jar包並沒有任何區別。

<dependency>
    <groupId>com.example.hello</groupId>
    <artifactId>hello</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

Maven子模塊和父模塊工程的替代方式

這個其實我們從上面也可以看出來,模塊之間的調用和普通的引入第三方的jar包沒有任何區別,只不過從上述提出的三個方面:

  1. 每個工程單獨管理,必然要開單獨的倉庫,是否能及時更新,及時響應,不好管理;
  2. 每個單獨的工程,那就要單端部署和管理,如何部署,是否在同一台服務器上,是否支持遠程調用,增加了運營運維的成本,不好管理;
  3. 如果每個都單獨開工程,那么有一部分的基礎代碼就會重復,比如POJO,各種配置,這些就會冗余。
    而言,這樣會比較麻煩,不管從運營,維護,以及更新,都會有一定的成本,所以就選擇了多層級的處理方式,但是實際上,還是單層級的項目最簡潔,這種方式代替也很簡單,就是一個模塊,當做是一個單獨的項目,如果有使用就去調用,至於是否支持遠程調用,那就要看是不是部署在同一個服務器上面,如果在同一台服務器,普通的方式就行,如果不在同一台服務器,那就要支持遠程調用,那就要用到RPC, Dubbo的方式了,更遠一步說,就是分布式架構微服務的范疇了,所以從這個角度上面來說,微服務,就是從這個角度出發的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM