一、分模塊設計與開發:讓項目結構更清晰
1.1 為什么需要分模塊?單模塊開發的痛點
在小型項目中,單模塊(所有代碼放在一個工程)或許能滿足需求,但項目規模擴大后會出現兩大核心問題:
- 維護成本高:幾十甚至上百個開發人員協作時,所有人操作同一個工程,代碼沖突頻繁,功能迭代時牽一發而動全身(比如改一個工具類可能影響多個業務模塊)。
- 資源復用難:項目中的通用組件(如實體類、工具類、統一響應封裝)無法單獨抽離,其他項目想使用時,只能復制粘貼或依賴整個工程(導致冗余代碼多、性能損耗大)。
1.2 分模塊設計的核心思路
分模塊設計的本質是 **“拆分” 與 “解耦”**:在項目設計階段,將一個大工程按功能或結構拆分為多個獨立子模塊,每個模塊專注于特定職責,模塊間通過依賴關系協作。
例如:電商項目可拆分為 “商品模塊”“訂單模塊”“購物車模塊”,同時抽離 “通用組件模塊”(存放實體類、工具類),各業務模塊只需依賴通用組件,無需重復編寫代碼。
1.3 3 種分模塊拆分策略(附實戰案例)
分模塊沒有固定標準,但需遵循 “高內聚、低耦合” 原則,常見有 3 種拆分策略:
拆分策略 | 核心思路 | 適用場景 | 工程結構示例 |
按功能模塊拆分 | 按業務功能劃分,每個模塊對應一個完整業務(如商品、訂單、搜索) | 業務邊界清晰的項目(如電商、CRM) | mall-common(通用組件)、mall-goods(商品)、mall-order(訂單)、mall-search(搜索) |
按層拆分 | 按技術分層劃分,每個模塊對應一個技術層(如控制層、業務層、數據層) | 技術架構標準化的項目(如中臺系統) | mall-common(通用)、mall-controller(控制層)、mall-service(業務層)、mall-mapper(數據層)、mall-pojo(實體類) |
功能 + 層混合拆分 | 先按功能拆分,再在每個功能模塊內部分層 | 大型復雜項目(如多端共用的后端系統) | mall-common(通用)、mall-goods-controller(商品控制層)、mall-goods-service(商品業務層)、mall-order-controller(訂單控制層) |
1.4 分模塊開發實戰步驟(以 “通用組件拆分” 為例)
以傳統 Web 工程為例,將 “實體類” 和 “工具類” 拆分為獨立模塊,步驟如下:
步驟 1:拆分 “實體類模塊”(xxx-pojo)
- 新建 Maven 模塊,命名為xxx-pojo(如 tlias-pojo),用途:存放所有實體類(如 User、Order、分頁結果 PageBean、統一響應 Result)。
- 在xxx-pojo的pom.xml中引入依賴(實體類常用依賴,如 Lombok、Spring 基礎依賴):
<dependencies> ????<!-- Lombok:簡化實體類get/set方法 --> ????<dependency> ????????<groupId>org.projectlombok</groupId> ????????<artifactId>lombok</artifactId> ????????<version>1.18.34</version> ????</dependency> ????<!-- Spring基礎依賴:支持@DateTimeFormat等注解 --> ????<dependency> ????????<groupId>org.springframework.boot</groupId> ????????<artifactId>spring-boot-starter</artifactId> ????????<version>3.2.8</version> ????</dependency> </dependencies> |
- 將原工程中com.xxx.pojo包下的所有類復制到xxx-pojo的對應包路徑下。
步驟 2:拆分 “工具類模塊”(xxx-utils)
- 新建 Maven 模塊,命名為xxx-utils,用途:存放通用工具類(如 JWT 工具、OSS 上傳工具、日期工具)。
- 在xxx-utils的pom.xml中引入工具類依賴(如 JWT、阿里云 OSS):
<dependencies> ????<!-- JWT:生成/解析令牌 --> ????<dependency> ????????<groupId>io.jsonwebtoken</groupId> ????????<artifactId>jjwt</artifactId> ????????<version>0.9.1</version> ????</dependency> ????<!-- 阿里云OSS:文件上傳 --> ????<dependency> ????????<groupId>com.aliyun.oss</groupId> ????????<artifactId>aliyun-sdk-oss</artifactId> ????????<version>3.17.4</version> ????</dependency> ????<!-- 依賴實體類模塊:工具類可能用到實體類 --> ????<dependency> ????????<groupId>com.xxx</groupId> ????????<artifactId>xxx-pojo</artifactId> ????????<version>1.0-SNAPSHOT</version> ????</dependency> </dependencies> |
- 將原工程中com.xxx.utils包下的工具類復制到xxx-utils的對應包路徑下。
步驟 3:改造原業務模塊(xxx-web-management)
- 刪除原工程中已拆分的pojo和utils包(避免沖突)。
- 在原業務模塊的pom.xml中引入拆分后的模塊依賴:
<dependencies> ????<!-- 依賴實體類模塊 --> ????<dependency> ????????<groupId>com.xxx</groupId> ????????<artifactId>xxx-pojo</artifactId> ????????<version>1.0-SNAPSHOT</version> ????</dependency> ????<!-- 依賴工具類模塊 --> ????<dependency> ????????<groupId>com.xxx</groupId> ????????<artifactId>xxx-utils</artifactId> ????????<version>1.0-SNAPSHOT</version> ????</dependency> </dependencies> |
1.5 分模塊開發的核心注意事項
- 先設計后開發:分模塊需在項目啟動前規劃好,避免先開發完再拆分(會導致大量代碼遷移和依賴調整)。
- 模塊邊界清晰:每個模塊的職責單一,避免出現 “一個模塊既包含商品業務,又包含訂單邏輯” 的情況。
- 依賴不循環:禁止出現 “模塊 A 依賴模塊 B,模塊 B 又依賴模塊 A” 的循環依賴(會導致 Maven 構建失敗)。
二、繼承與聚合:解決依賴混亂,實現一鍵構建
分模塊后,會出現新問題:多個模塊依賴重復(如每個模塊都要引入 Lombok)、版本管理麻煩(改一個依賴版本需改所有模塊)、構建時需手動按依賴順序執行(如先構建 pojo,再構建 utils,最后構建業務模塊)。Maven 的 “繼承” 和 “聚合” 特性可完美解決這些問題。
2.1 繼承:統一管理依賴,簡化配置
2.1.1 繼承的核心作用
- 簡化依賴配置:將多個模塊的公共依賴(如 Lombok、Spring Boot Starter)提取到 “父工程”,子模塊無需重復配置,自動繼承父工程依賴。
- 統一版本管理:父工程定義依賴版本,子模塊直接使用,避免版本不一致導致的兼容性問題。
2.1.2 繼承的實現步驟(以 Spring Boot 項目為例)
Spring Boot 項目默認繼承spring-boot-starter-parent,因此我們需要創建 “自定義父工程”,讓自定義父工程繼承 Spring Boot 父工程,再讓業務模塊繼承自定義父工程(支持多重繼承)。
步驟 1:創建自定義父工程(xxx-parent)
- 新建 Maven 模塊,命名為xxx-parent,打包方式必須為 pom(父工程僅用于依賴管理,不寫業務代碼,無需 src 目錄,可刪除)。
- 在父工程的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 ?????????????????????????????http://maven.apache.org/xsd/maven-4.0.0.xsd"> ????<modelVersion>4.0.0</modelVersion> ????<!-- 繼承Spring Boot官方父工程 --> ????<parent> ????????<groupId>org.springframework.boot</groupId> ????????<artifactId>spring-boot-starter-parent</artifactId> ????????<version>3.2.8</version> ????????<relativePath/> <!-- 從倉庫查找父工程,不指定本地路徑 --> ????</parent> ????<!-- 自定義父工程坐標 --> ????<groupId>com.xxx</groupId> ????<artifactId>xxx-parent</artifactId> ????<version>1.0-SNAPSHOT</version> ????<packaging>pom</packaging> <!-- 父工程打包方式必須為pom --> ????<!-- 1. 配置公共依賴(子模塊自動繼承) --> ????<dependencies> ????????<!-- Lombok:所有模塊通用 --> ????????<dependency> ????????????<groupId>org.projectlombok</groupId> ????????????<artifactId>lombok</artifactId> ????????????<version>1.18.34</version> ????????</dependency> ????????<!-- Spring基礎依賴:所有模塊通用 --> ????????<dependency> ????????????<groupId>org.springframework.boot</groupId> ????????????<artifactId>spring-boot-starter</artifactId> ????????</dependency> ????</dependencies> ????<!-- 2. 版本鎖定(非公共依賴,僅統一版本,子模塊需手動引入) --> ????<dependencyManagement> ????????<dependencies> ????????????<!-- JWT:僅部分模塊使用,統一版本 --> ????????????<dependency> ????????????????<groupId>io.jsonwebtoken</groupId> ????????????????<artifactId>jjwt</artifactId> ????????????????<version>0.9.1</version> ????????????</dependency> ????????????<!-- 阿里云OSS:僅工具類模塊使用,統一版本 --> ????????????<dependency> ????????????????<groupId>com.aliyun.oss</groupId> ????????????????<artifactId>aliyun-sdk-oss</artifactId> ????????????????<version>3.17.4</version> ????????????</dependency> ????????</dependencies> ????</dependencyManagement> ????<!-- 3. 自定義屬性(集中管理版本號,便于修改) --> ????<properties> ????????<maven.compiler.source>17</maven.compiler.source> <!-- JDK版本 --> ????????<maven.compiler.target>17</maven.compiler.target> ????????<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> ????????<!-- 依賴版本屬性(可直接引用) --> ????????<lombok.version>1.18.34</lombok.version> ????????<jwt.version>0.9.1</jwt.version> ????</properties> </project> |
步驟 2:子模塊繼承父工程
在每個子模塊(如 xxx-pojo、xxx-utils)的pom.xml中配置繼承:
<parent> ????<groupId>com.xxx</groupId> ????<artifactId>xxx-parent</artifactId> ????<version>1.0-SNAPSHOT</version> ????<!-- 父工程pom.xml的相對路徑(若父工程與子模塊平級,路徑為../xxx-parent/pom.xml) --> ????<relativePath>../xxx-parent/pom.xml</relativePath> </parent> <!-- 子模塊坐標:groupId可省略(繼承父工程),僅需配置artifactId和version --> <artifactId>xxx-pojo</artifactId> <version>1.0-SNAPSHOT</version> |
步驟 3:子模塊引入依賴(無需版本號)
若依賴已在父工程的dependencyManagement中鎖定版本,子模塊引入時無需寫version:
<!-- 子模塊xxx-utils引入JWT依賴(版本由父工程統一管理) --> <dependencies> ????<dependency> ????????<groupId>io.jsonwebtoken</groupId> ????????<artifactId>jjwt</artifactId> ????</dependency> </dependencies> |
2.1.3 關鍵知識點:dependencyManagement?vs dependencies
很多人會混淆這兩個標簽,核心區別如下:
特性 | <dependencies> | <dependencyManagement> |
作用 | 直接引入依賴,子模塊自動繼承 | 僅統一管理依賴版本,不自動引入依賴 |
子模塊使用方式 | 無需額外配置,直接使用 | 需手動引入依賴,無需寫 version |
適用場景 | 所有子模塊都需要的公共依賴(如 Lombok) | 部分子模塊需要的依賴(如 JWT、OSS) |
2.2 聚合:一鍵構建所有模塊,無需手動排序
2.2.1 聚合的核心作用
分模塊后,模塊間有依賴關系(如 xxx-web 依賴 xxx-utils,xxx-utils 依賴 xxx-pojo),手動構建時需按 “pojo → utils → web” 的順序執行,否則會因依賴缺失失敗。
聚合可將所有模塊納入 “聚合工程”,執行一次構建命令(如mvn package),Maven 會自動按依賴順序構建所有模塊,實現 “一鍵構建”。
2.2.2 聚合的實現步驟
通常將 “父工程” 同時作為 “聚合工程”(無需額外創建聚合工程),步驟如下:
- 在父工程(xxx-parent)的pom.xml中配置modules標簽,指定需要聚合的子模塊:
<!-- 聚合工程:指定子模塊路徑(相對路徑) --> <modules> ????<!-- 若子模塊與父工程平級,路徑為../xxx-pojo --> ????<module>../xxx-pojo</module> ????<module>../xxx-utils</module> ????<module>../xxx-web-management</module> </modules> |
- 執行聚合構建:在父工程根目錄執行 Maven 命令(如mvn clean package),Maven 會自動按依賴順序構建所有子模塊:
- 先構建xxx-pojo(無依賴)
- 再構建xxx-utils(依賴 xxx-pojo)
- 最后構建xxx-web-management(依賴 xxx-utils 和 xxx-pojo)
2.2.3 聚合的注意事項
- 聚合工程的打包方式必須為pom。
- modules中模塊的順序不影響構建順序(Maven 會自動分析依賴關系)。
- 若需排除某個模塊,只需從modules中刪除該模塊的配置即可。
2.3 繼承與聚合的對比總結
特性 | 繼承(Inheritance) | 聚合(Aggregation) |
核心目標 | 簡化依賴配置、統一版本 | 一鍵構建所有模塊,自動排序 |
配置位置 | 子模塊的 pom.xml 中(配置 parent 標簽) | 聚合工程的 pom.xml 中(配置 modules 標簽) |
感知關系 | 父工程無法感知哪些子模塊繼承了自己 | 聚合工程能感知所有被聚合的子模塊 |
共同點 | 打包方式均為 pom,無業務代碼,僅做配置管理 |
實際開發中,父工程通常同時承擔 “繼承” 和 “聚合” 的角色(如 xxx-parent 既是父工程,也是聚合工程),這樣既能統一管理依賴,又能一鍵構建所有模塊。
三、私服:解決團隊內部資源共享與同步
分模塊開發后,模塊如何在團隊內部共享?比如 A 團隊開發的xxx-utils模塊,B 團隊想使用,直接復制代碼會導致版本不一致,上傳到中央倉庫又無權限(中央倉庫僅接受開源項目)。Maven 私服可解決這一問題。
3.1 私服的核心概念與作用
3.1.1 什么是私服?
私服是架設在企業局域網內的 “私有 Maven 倉庫”,本質是 “中央倉庫的代理”+“團隊內部資源庫”:
- 代理中央倉庫:當本地倉庫沒有依賴時,先從私服下載;私服沒有則自動從中央倉庫下載,緩存到私服,下次其他團隊成員可直接從私服獲取。
- 存儲內部資源:團隊開發的模塊(如xxx-utils)可上傳到私服,其他團隊通過依賴坐標直接引用,無需復制代碼。
3.1.2 為什么需要私服?
- 資源共享安全可控:內部模塊無需上傳公網,既能保護代碼隱私,又能避免因代碼復制導致的版本不一致(如 A 團隊更新
xxx-utils
后,B 團隊通過依賴更新即可同步,無需手動替換代碼); - 提升依賴下載效率:局域網內下載速度遠快于外網,尤其在團隊成員多、外網不穩定時,可大幅減少依賴等待時間;
- 規避中央倉庫權限限制:公網中央倉庫僅允許特定機構上傳資源,企業自研的私有模塊無法上傳,私服則支持團隊自主管理上傳權限。
3.1.3 依賴查找順序
Maven 項目引入依賴時,會按以下優先級查找,直至獲取依賴:
- 本地倉庫:優先查詢開發者本地
.m2/repository
目錄; - 私服倉庫:本地倉庫缺失時,自動請求企業私服;
- 中央倉庫:私服無該依賴時,由私服代理下載并緩存,供后續使用。
注:企業中通常僅需搭建 1 臺私服,開發人員無需自行搭建,掌握配置和使用即可。
3.2 私服倉庫分類與版本規范
3.2.1 私服倉庫類型
私服默認包含 3 類倉庫,各司其職:
- RELEASE 倉庫:存儲功能穩定、停止更新的 “發布版本” 模塊(如
xxx-utils-1.0.RELEASE.jar
),用于生產環境; - SNAPSHOT 倉庫:存儲處于開發中、需頻繁迭代的 “快照版本” 模塊(如
xxx-utils-1.0-SNAPSHOT.jar
),用于測試和開發環境; - Central 倉庫:代理公網中央倉庫,緩存第三方依賴,避免重復從外網獲取。
3.2.2 項目版本規范
- RELEASE 版本:版本號格式為
主版本號.次版本號.修訂號
(如 1.0.0),表示功能成熟、無重大 bug,對應上傳至 RELEASE 倉庫; - SNAPSHOT 版本:版本號末尾加
-SNAPSHOT
(如 1.0.0-SNAPSHOT),表示仍在迭代,對應上傳至 SNAPSHOT 倉庫。
3.3 私服資源上傳與下載實戰
3.3.1 核心配置步驟
實現私服資源的上傳與下載,需完成 3 步配置,最終執行deploy
命令即可:
步驟 1:配置私服訪問憑證(settings.xml)
在 Maven 安裝目錄的conf/settings.xml
中,添加私服的用戶名和密碼(由管理員提供,默認常為admin/admin
):
xml
<servers><!-- RELEASE倉庫訪問憑證 --><server><id>maven-releases</id><username>admin</username><password>admin</password></server><!-- SNAPSHOT倉庫訪問憑證 --><server><id>maven-snapshots</id><username>admin</username><password>admin</password></server>
</servers>
注:id
需與后續項目 pom.xml 中的倉庫 ID 保持一致,否則無法匹配權限。
步驟 2:配置私服下載地址(settings.xml)
同樣在settings.xml
中,配置鏡像和倉庫權限,讓 Maven 優先從私服下載依賴:
xml
<!-- 鏡像:所有依賴請求轉發到私服 -->
<mirrors><mirror><id>maven-public</id><mirrorOf>*</mirrorOf><url>http://localhost:8081/repository/maven-public/</url> <!-- 私服公共倉庫地址 --></mirror>
</mirrors><!-- 允許下載RELEASE和SNAPSHOT版本 -->
<profiles><profile><id>allow-snapshots</id><activation><activeByDefault>true</activeByDefault> <!-- 默認激活 --></activation><repositories><repository><id>maven-public</id><url>http://localhost:8081/repository/maven-public/</url><releases><enabled>true</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository></repositories></profile>
</profiles>
步驟 3:配置項目上傳地址(pom.xml)
在父工程 pom.xml 中,添加distributionManagement
標簽,指定不同版本的上傳路徑:
xml
<distributionManagement><!-- RELEASE版本上傳地址 --><repository><id>maven-releases</id> <!-- 與settings.xml中server的id一致 --><url>http://localhost:8081/repository/maven-releases/</url></repository><!-- SNAPSHOT版本上傳地址 --><snapshotRepository><id>maven-snapshots</id> <!-- 與settings.xml中server的id一致 --><url>http://localhost:8081/repository/maven-snapshots/</url></snapshotRepository>
</distributionManagement>
3.3.2 執行上傳與下載
- 資源上傳:在父工程根目錄執行
mvn clean deploy
,Maven 會自動根據版本類型(RELEASE/SNAPSHOT)上傳至對應倉庫,可通過私服管理界面(如http://localhost:8081
)查看; - 資源下載:其他項目組需使用時,直接在 pom.xml 中引入依賴坐標,Maven 會按 “本地→私服→中央倉庫” 順序自動下載。
示例:引入私服中的xxx-utils
模塊
xml
<dependency><groupId>com.xxx</groupId><artifactId>xxx-utils</artifactId><version>1.0-SNAPSHOT</version> <!-- 版本需與私服一致 -->
</dependency>
3.4 關鍵注意事項
- 地址與 ID 一致性:確保
settings.xml
和pom.xml
中的私服地址、倉庫 ID 完全匹配,否則會出現 “權限拒絕” 或 “連接失敗”; - 版本規范使用:禁止將 SNAPSHOT 版本上傳至 RELEASE 倉庫,避免影響生產環境穩定性;
- 企業環境適配:真實開發中,私服部署在遠程服務器,需將配置中的
localhost
替換為實際 IP / 域名,并確保開發環境可訪問該服務器; - 依賴沖突處理:若私服存在多版本依賴,優先使用項目指定版本,或通過父工程
dependencyManagement
統一鎖定版本。