前言
在使用 Maven 構建 Java 項目時,我們常常需要對項目的打包過程進行精細化控制,尤其是希望排除某些特定的依賴庫。這可能是為了減小最終構建產物的體積、避免版本沖突,或者僅僅是為了滿足不同環境下的部署需求。
本文將詳細介紹如何在 Maven 打包過程中排除特定依賴,涵蓋多種常見插件和配置方式,幫助你靈活控制項目的打包內容。
一、理解 Maven 的依賴作用域(Scope)
在深入討論排除依賴之前,先了解 Maven 中的依賴作用域是非常重要的。不同的作用域決定了依賴是否會被包含在構建輸出中:
Scope | 描述 |
---|---|
compile | 默認作用域,適用于所有階段(編譯、測試、運行) |
provided | 編譯和測試階段可用,但不會被打包進最終輸出(如 Servlet API) |
runtime | 運行和測試階段需要,但編譯不需要(如 JDBC 驅動) |
test | 僅用于測試階段,不會被打包 |
system | 類似于 provided,但必須顯式指定本地路徑 |
import | 僅用于 <dependencyManagement> 中導入其他 POM 的依賴 |
最佳實踐建議:優先使用合適的 scope 來控制依賴是否被打包,而不是通過插件強行剔除。
二、使用 Maven Shade Plugin 排除依賴
如果你使用的是 maven-shade-plugin
來構建一個包含所有依賴的 fat jar(即 uber jar),可以通過 <excludes>
標簽來排除特定依賴。
示例配置:
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.5.0</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><excludes><exclude>com.example:unwanted-library</exclude><exclude>org.slf4j:slf4j-simple</exclude></excludes><transformers><transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><mainClass>com.example.Main</mainClass></transformer></transformers></configuration></execution></executions>
</plugin>
說明:
<exclude>
的格式為groupId:artifactId
,可以精確到版本號。- 適合用于構建包含多個模塊和依賴的單體 JAR 包。
三、使用 Maven Assembly Plugin 排除依賴
如果你使用 maven-assembly-plugin
來打包一個包含依賴的 zip/jar 包,也可以通過 <excludes>
來排除某些依賴。
示例配置:
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>3.6.0</version><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><archive><manifest><mainClass>com.example.Main</mainClass></manifest></archive><excludes><exclude>com.example:unwanted-library</exclude><exclude>org.slf4j:slf4j-api</exclude></excludes></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions>
</plugin>
提示:Assembly 插件還支持自定義 assembly.xml
文件,實現更細粒度的控制。
四、使用 Maven Jar Plugin 排除資源或類文件
默認的 maven-jar-plugin
不會把依賴打進 JAR 包中,但如果你有特殊需求(如手動管理 lib 目錄),可以用來排除某些資源或類文件。
示例配置(排除資源):
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.7.0</version><configuration><excludes><exclude>**/unwanted/**</exclude></excludes></configuration>
</plugin>
五、使用 Maven Dependency Plugin 清理依賴
如果你想在打包前主動清理某些依賴,可以使用 maven-dependency-plugin
來復制依賴并排除部分庫。
示例配置:
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><version>3.6.0</version><executions><execution><id>copy-dependencies</id><phase>package</phase><goals><goal>copy-dependencies</goal></goals><configuration><outputDirectory>${project.build.directory}/lib</outputDirectory><overWriteReleases>false</overWriteReleases><overWriteSnapshots>false</overWriteSnapshots><overWriteIfNewer>true</overWriteIfNewer><excludes><exclude>com.example:unwanted-library</exclude></excludes></configuration></execution></executions>
</plugin>
此方法適合手動構建 lib 目錄,并配合 shell 腳本或 Dockerfile 使用。
六、Docker 構建中排除依賴(Maven + Docker)
如果你使用 Maven 構建鏡像(如結合 Jib、Dockerfile 等),可以在構建應用 JAR 包時就排除依賴,再將其 COPY 到 Docker 鏡像中。
示例(結合 jib-maven-plugin):
<plugin><groupId>com.google.cloud.tools</groupId><artifactId>jib-maven-plugin</artifactId><version>3.3.2</version><configuration><container><entrypoint><arg>java</arg><arg>-cp</arg><arg>/app/resources:/app/classes:/app/libs/*</arg><arg>com.example.Main</arg></entrypoint></container><extraDirectories><paths><path><from>src/main/resources</from><into>/app/resources</into></path></paths></extraDirectories></configuration>
</plugin>
在此示例中,你可以先通過其他方式控制哪些依賴被放入 /app/libs/
。
七、使用 <scope>
顯式排除依賴
最簡單且推薦的方式是直接在 pom.xml
中設置依賴的作用域為 test
或 provided
,這樣它們就不會被打包進最終輸出。
示例:
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope>
</dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope>
</dependency>
Maven 會根據作用域自動決定是否將該依賴包含在構建輸出中。
八、使用 <optional>
標記依賴為可選
如果你開發的是一個庫(library),并且某個依賴不是必需的,可以將其標記為 <optional>true</optional>
,這樣引入你的庫的項目可以選擇是否包含這個依賴。
示例:
<dependency><groupId>com.example</groupId><artifactId>some-utils</artifactId><version>1.0.0</version><optional>true</optional>
</dependency>
注意:<optional>
不會影響當前項目的打包行為,而是影響下游項目的依賴管理。
九、使用 <exclusion>
排除傳遞性依賴
有時你想排除某個依賴的子依賴(transitive dependency),可以使用 <exclusions>
。
示例:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion><exclusion><groupId>org.slf4j</groupId><artifactId>log4j-over-slf4j</artifactId></exclusion></exclusions>
</dependency>
這種方式非常適合解決依賴沖突或精簡依賴樹。
十、綜合建議與最佳實踐
場景 | 推薦做法 |
---|---|
測試依賴不打包 | 設置 <scope>test</scope> |
容器已提供依賴(如 Tomcat、JDK) | 設置 <scope>provided</scope> |
某些依賴不想被打入最終 JAR/WAR | 使用 Shade / Assembly 插件配置 <excludes> |
排除某個依賴的子依賴 | 使用 <exclusions> 標簽 |
控制依賴是否傳遞給下游項目 | 使用 <optional>true</optional> |
構建 lib 目錄時排除某些庫 | 使用 maven-dependency-plugin 的 <excludes> |
構建 Docker 鏡像時排除依賴 | 結合上述方法先處理好 JAR 再 COPY |
總結
Maven 提供了多種靈活的方式來排除特定依賴,從簡單的 <scope>
到復雜的插件配置,開發者可以根據實際需求選擇最合適的方法。合理使用這些技巧不僅可以減小最終包的體積,還能有效避免依賴沖突問題,提高構建效率和部署穩定性。
常見問答
Q:我只想排除某個依賴的一個 jar 文件?
A:可以使用 <exclusion>
排除其子依賴,或者使用插件配置 <excludes>
。
Q:為什么設置了 <scope>provided</scope>
依賴仍然被打包?
A:檢查是否被其他插件強制引入,例如 maven-shade-plugin
。
Q:我想在 Spring Boot 項目中排除某些 starter 自帶的依賴怎么辦?
A:使用 <exclusions>
標簽,在對應的 starter 依賴中聲明要排除的子依賴。