<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Maven 劃分模塊最佳實(shí)踐

          共 10421字,需瀏覽 21分鐘

           ·

          2021-10-27 15:15

          往期熱門文章:

          1、面試官問:select......for update會鎖表還是鎖行?

          2、Spring Boot + GraphQL 才是 API 的未來!

          3、一個基于 SpringBoot2+redis+Vue 的商城管理系統(tǒng),拼團(tuán)、砍價、秒殺等都有,可二次開發(fā)接私活!

          4、用 MySQL 實(shí)現(xiàn)分布式鎖,你聽過嗎?

          5、全員遠(yuǎn)程辦公,半年入 1 億美元:GitHub 的最大競爭對手上市了!


          所有用Maven管理的真實(shí)的項(xiàng)目都應(yīng)該是分模塊的,每個模塊都對應(yīng)著一個pom.xml。它們之間通過繼承和聚合(也稱作多模塊,multi-module)相互關(guān)聯(lián)。那么,為什么要這么做呢?我們明明在開發(fā)一個項(xiàng)目,劃分模塊后,導(dǎo)入Eclipse變成了N個項(xiàng)目,這會帶來復(fù)雜度,給開發(fā)帶來不便。


          為了解釋原因,假設(shè)有這樣一個項(xiàng)目,很常見的Java Web應(yīng)用。在這個應(yīng)用中,我們分了幾層:

          • Dao層負(fù)責(zé)數(shù)據(jù)庫交互,封裝了Hibernate交互的類。

          • Service層處理業(yè)務(wù)邏輯,放一些Service接口和實(shí)現(xiàn)相關(guān)的Bean。

          • Web層負(fù)責(zé)與客戶端交互,主要有一些Structs的Action類。

          對應(yīng)的,在一個項(xiàng)目中,我們會看到一些包名:

          • org.myorg.app.dao

          • org.myorg.app.service

          • org.myorg.app.web

          • org.myorg.app.util

          這樣整個項(xiàng)目的框架就清晰了,但隨著項(xiàng)目的進(jìn)行,你可能會遇到如下問題:
          這個應(yīng)用可能需要有一個前臺和一個后臺管理端(web或者swing),你發(fā)現(xiàn)大部分dao,一些service,和大部分util是在兩個應(yīng)用中可用的。這樣的問題,你一周內(nèi)遇到了好幾次。
          pom.xml中的依賴列表越來越長以重用的,但是,由于目前只有一個項(xiàng)目(WAR),你不得不新建一個項(xiàng)目依賴這個WAR,這變得非常的惡心,因?yàn)樵贛aven中配置對WAR的依賴遠(yuǎn)不如依賴JAR那樣簡單明了,而且你根本不需要org.myorg.app.web。有人修改了dao,提交到svn并且不小心導(dǎo)致build失敗了,你在編寫service的代碼,發(fā)現(xiàn)編譯不過,只能等那人把dao修復(fù)了,你才能繼續(xù)進(jìn)行,很多人都在修改,到后來你根本就不清楚哪個依賴是誰需要的,漸漸的,很多不必要的依賴被引入。甚至出現(xiàn)了一個依賴有多個版本存在。
          build整個項(xiàng)目的時間越來越長,盡管你只是一直在web層工作,但你不得不build整個項(xiàng)目。
          某個模塊,比如util,你只想讓一些經(jīng)驗(yàn)豐富的人來維護(hù),可是,現(xiàn)在這種情況,每個開發(fā)者都能修改,這導(dǎo)致關(guān)鍵模塊的代碼質(zhì)量不能達(dá)到你的要求。
          我們會發(fā)現(xiàn),其實(shí)這里實(shí)際上沒有遵守一個設(shè)計(jì)模式原則:“高內(nèi)聚,低耦合”。雖然我們通過包名劃分了層次,并且你還會說,這些包的依賴都是單向的,沒有包的環(huán)依賴。這很好,但還不夠,因?yàn)榫蜆?gòu)建層次來說,所有東西都被耦合在一起了。因此我們需要使用Maven劃分模塊。

          一個簡單的Maven模塊結(jié)構(gòu)是這樣的:

           1---- app-parent
          2|-- pom.xml (pom)
          3|
          4|-- app-util
          5|        |-- pom.xml (jar)
          6|
          7|-- app-dao
          8|        |-- pom.xml (jar)
          9|
          10|-- app-service
          11|        |-- pom.xml (jar)
          12|
          13|-- app-web
          14|-- pom.xml (war)

          上述簡單示意圖中,有一個父項(xiàng)目(app-parent)聚合很多子項(xiàng)目(app-util, app-dao, app-service, app-web)。每個項(xiàng)目,不管是父子,都含有一個pom.xml文件。而且要注意的是,小括號中標(biāo)出了每個項(xiàng)目的打包類型。父項(xiàng)目是pom,也只能是pom。子項(xiàng)目有jar,或者war。根據(jù)它包含的內(nèi)容具體考慮。

          這些模塊的依賴關(guān)系如下:

          1app-dao      --> app-util
          2app-service  --> app-dao
          3app-web      --> app-service

          注意依賴的傳遞性(大部分情況是傳遞的,除非你配置了特殊的依賴scope),app-dao依賴于app-util,app-service依賴于app-dao,于是app-service也依賴于app-util。同理,app-web依賴于app-dao,app-util。

          項(xiàng)目層次的劃分代包層次的劃分能給我們帶來如下好處:

          • 方便重用,如果你有一個新的swing項(xiàng)目需要用到app-dao和app-service,添加對它們的依賴即可,你不再需要去依賴一個WAR。而有些模塊,如app-util,完全可以漸漸進(jìn)化成公司的一份基礎(chǔ)工具類庫,供所有項(xiàng)目使用。這是模塊化最重要的一個目的。

          • 由于你現(xiàn)在劃分了模塊,每個模塊的配置都在各自的pom.xml里,不用再到一個混亂的紛繁復(fù)雜的總的POM中尋找自己的配置。

          • 如果你只是在app-dao上工作,你不再需要build整個項(xiàng)目,只要在app-dao目錄運(yùn)行mvn命令進(jìn)行build即可,這樣可以節(jié)省時間,尤其是當(dāng)項(xiàng)目越來越復(fù)雜,build越來越耗時后。

          • 某些模塊,如app-util被所有人依賴,但你不想給所有人修改,現(xiàn)在你完全可以從這個項(xiàng)目結(jié)構(gòu)出來,做成另外一個項(xiàng)目,svn只給特定的人訪問,但仍提供jar給別人使用。

          • 多模塊的Maven項(xiàng)目結(jié)構(gòu)支持一些Maven的更有趣的特性(如DepencencyManagement),這留作以后討論。

          • 接下來討論一下POM配置細(xì)節(jié),實(shí)際上非常簡單,先看app-parent的pom.xml

           1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          2xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

          3<modelVersion>4.0.0</modelVersion>
          4<groupId>org.myorg.myapp</groupId>
          5<artifactId>app-parent</artifactId>
          6<packaging>pom</packaging>
          7<version>1.0-SNAPSHOT</version>
          8<modules>
          9    <module>app-util</module>
          10    <module>app-dao</module>
          11    <module>app-service</module>
          12    <module>app-web</module>
          13</modules>
          14</project>

          Maven的坐標(biāo)GAV(groupIdartifactIdversion)在這里進(jìn)行配置,這些都是必須的。特殊的地方在于,這里的packagingpom。所有帶有子模塊的項(xiàng)目的packaging都為pom。packaging如果不進(jìn)行配置,它的默認(rèn)值是jar,代表Maven會將項(xiàng)目打成一個jar包。
          該配置重要的地方在于modules,例子中包含的子模塊有app-util, app-dao, app-service, app-war。在Maven build app-parent的時候,它會根據(jù)子模塊的相互依賴關(guān)系整理一個build順序,然后依次build。
          這就是一個父模塊大概需要的配置,接下來看一下子模塊符合配置繼承父模塊。

           1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          2xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

          3<parent>
          4<artifactId>app-parent</artifactId>
          5<groupId>org.myorg.myapp</groupId>
          6<version>1.0-SNAPSHOT</version>
          7</parent>
          8<modelVersion>4.0.0</modelVersion>
          9<artifactId>app-util</artifactId>
          10<dependencies>
          11    <dependency>
          12        <groupId>commons-lang</groupId>
          13        <artifactId>commons-lang</artifactId>
          14        <version>2.4</version>
          15   </dependency>
          16</dependencies>
          17</project>

          app-util模塊繼承了app-parent父模塊,因此這個POM的一開始就聲明了對app-parent的引用,該引用是通過Maven坐標(biāo)GAV實(shí)現(xiàn)的。而關(guān)于項(xiàng)目app-util本身,它卻沒有聲明完整GAV,這里我們只看到了artifactId。這個POM并沒有錯,groupId和version默認(rèn)從父模塊繼承了。實(shí)際上子模塊從父模塊繼承一切東西,包括依賴,插件配置等等。
          此外app-util配置了一個對于commons-lang的簡單依賴,這是最簡單的依賴配置形式。大部分情況,也是通過GAV引用的。
          再看一下app-dao,它也是繼承于app-parent,同時依賴于app-util:

           1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          2xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

          3<parent>
          4<artifactId>app-parent</artifactId>
          5<groupId>org.myorg.myapp</groupId>
          6<version>1.0-SNAPSHOT</version>
          7</parent>
          8<modelVersion>4.0.0</modelVersion>
          9<artifactId>app-dao</artifactId>
          10<dependencies>
          11       <dependency>
          12         <groupId>org.myorg.myapp</groupId>
          13         <artifactId>app-util</artifactId>
          14         <version>${project.version}</version>
          15    </dependency>
          16</dependencies>
          17</project>

          該配置和app-util的配置幾乎沒什么差別,不同的地方在于,依賴變化了,app-dao依賴于app-util。這里要注意的是version的值為${project.version},這個值是一個屬性引用,指向了POM的project/version的值,也就是這個POM對應(yīng)的version。由于app-dao的version繼承于app-parent,因此它的值就是1.0-SNAPSHOT。而app-util也繼承了這個值,因此在所有這些項(xiàng)目中,我們做到了保持版本一致。
          這里還需要注意的是,app-dao依賴于app-util,而app-util又依賴于commons-lang,根據(jù)傳遞性,app-dao也擁有了對于commons-lang的依賴。
          app-service我們跳過不談,它依賴于app-dao。我們最后看一下app-web:

           1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          2xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

          3<parent>
          4<artifactId>app-parent</artifactId>
          5<groupId>org.myorg.myapp</groupId>
          6<version>1.0-SNAPSHOT</version>
          7</parent>
          8<modelVersion>4.0.0</modelVersion>
          9<artifactId>app-web</artifactId>
          10<packaging>war</packaging>
          11<dependencies>
          12    <dependency>
          13        <groupId>org.myorg.myapp</groupId>
          14        <artifactId>app-service</artifactId>
          15        <version>${project.version}</version>
          16    </dependency>
          17</dependencies>
          18</project>

          app-web依賴于app-service,因此配置了對其的依賴。
          由于app-web是我們最終要部署的應(yīng)用,因此它的packaging是war。為此,你需要有一個目錄
          src/main/webapp。并在這個目錄下?lián)碛衱eb應(yīng)用需要的文件,如/WEB-INF/web.xml。沒有web.xml,Maven會報(bào)告build失敗,此外你可能還會有這樣一些子目錄:/js, /img, /css … 。

          看看Maven是如何build整個項(xiàng)目的,我們在 app-parent 根目錄中運(yùn)行 mvn clean install ,輸出的末尾會有大致這樣的內(nèi)容:

           1...
          2...
          3[INFO] [war:war]
          4[INFO] Packaging webapp
          5[INFO] Assembling webapp[app-web] in [/home/juven/workspaces/ws-others/myapp/app-web/target/app-web-1.0-SNAPSHOT]
          6[INFO] Processing war project
          7[INFO] Webapp assembled in[50 msecs]
          8[INFO] Building war: /home/juven/workspaces/ws-others/myapp/app-web/target/app-web-1.0-SNAPSHOT.war
          9[INFO] [install:install]
          10[INFO] Installing /home/juven/workspaces/ws-others/myapp/app-web/target/app-web-1.0-SNAPSHOT.war to /home/juven/.m2/repository/org/myorg/myapp/app-web/1.0-SNAPSHOT/app-web-1.0-SNAPSHOT.war
          11[INFO]
          12[INFO]
          13[INFO] ------------------------------------------------------------------------
          14[INFO] Reactor Summary:
          15[INFO] ------------------------------------------------------------------------
          16[INFO] app-parent ............................................ SUCCESS [1.191s]
          17[INFO] app-util .............................................. SUCCESS [1.274s]
          18[INFO] app-dao ............................................... SUCCESS [0.583s]
          19[INFO] app-service ........................................... SUCCESS [0.593s]
          20[INFO] app-web ............................................... SUCCESS [0.976s]
          21[INFO] ------------------------------------------------------------------------
          22[INFO] ------------------------------------------------------------------------
          23[INFO] BUILD SUCCESSFUL
          24[INFO] ------------------------------------------------------------------------
          25[INFO] Total time: 4 seconds
          26[INFO] Finished at: Sat Dec 27 08:20:18 PST 2008
          27[INFO] Final Memory: 3M/17M
          28[INFO] ------------------------------------------------------------------------

          注意Reactor Summary,整個項(xiàng)目根據(jù)我們希望的順序進(jìn)行build。Maven根據(jù)我們的依賴配置,智能的安排了順序,app-util, app-dao, app-service, app-web。

          最后,你可以在 app-web/target 目錄下找到文件 app-web-1.0-SNAPSHOT.war ,打開這個war包,在 /WEB-INF/lib 目錄看到了 commons-lang-2.4.jar,以及對應(yīng)的app-util, app-dao, app-service 的jar包。Maven自動幫你處理了打包的事情,并且根據(jù)你的依賴配置幫你引入了相應(yīng)的jar文件。

          使用多模塊的Maven配置,可以幫助項(xiàng)目劃分模塊,鼓勵重用,防止POM變得過于龐大,方便某個模塊的構(gòu)建,而不用每次都構(gòu)建整個項(xiàng)目,并且使得針對某個模塊的特殊控制更為方便。本文同時給出了一個實(shí)際的配置樣例,展示了如何使用Maven配置多模塊項(xiàng)目。

          最近熱文閱讀:

          1、面試官問:select......for update會鎖表還是鎖行?
          2、Spring Boot + GraphQL 才是 API 的未來!
          3、一個基于 SpringBoot2+redis+Vue 的商城管理系統(tǒng),拼團(tuán)、砍價、秒殺等都有,可二次開發(fā)接私活!
          4、用 MySQL 實(shí)現(xiàn)分布式鎖,你聽過嗎?
          5、全員遠(yuǎn)程辦公,半年入 1 億美元:GitHub 的最大競爭對手上市了!
          6、面試官:Spring AOP、AspectJ、CGLIB 都是什么鬼?它們有什么關(guān)系?
          7、10 個 VSCode 超級摸魚神器,確定不試一下?
          8、JMH + Arthas,性能監(jiān)控的神器
          9、MySQL 8.0 可以操作 JSON 了,牛逼
          10、for循環(huán)里用+號拼接字符串的小姐姐,今天已經(jīng)離職了
          關(guān)注公眾號,你想要的Java都在這里

          瀏覽 61
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一本色道久久88亚洲综合加勒比 | 国产激情在线观看视频 | 日韩午夜福利视频 | 欧美操逼视| 日本成人三级片在线观看 |