一、背景
一般情況下會認為 maven 是給Java工程使用的,但實際並不是,一個程序由多方構成,包括:自己編寫的程序代碼、依賴的第三方程序(可能是jar、可能就是一個二進制文件、或這個C++庫等),基於此,自己編寫的程序可以直接通過 maven依賴將自己需要的第三方程序自動加載到本地。
二、場景
1、 程序依賴的第三方程序在一個zip包中,目前需要將該 zip 通過 maven 依賴進來,程序打包生成成果物的時候,需要將zip包解壓放到指定的目錄中,供自己的程序執行時可調用。
這里僅是舉簡單的例子:
(1) 依賴的第三方zip包生成
工程目錄結構:

這里通過pom.xml 及 assembly-zip-deploy.xml 將 consul 二進制文件打包 到一個 zip包中,可以看下這兩個文件的配置內容。
pom.xml
<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> <groupId>com.summer</groupId> <artifactId>maven-assembly-demo</artifactId> <packaging>pom</packaging> <version>0.0.1-SNAPSHOT</version> <name>maven-assembly-demo</name> <description>demo for maven-assembly-plugin</description> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <id>assembly-package</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> <configuration> <descriptors> <descriptor>assembly-zip-deploy.xml</descriptor> </descriptors> <outputDirectory>output</outputDirectory> </configuration> </plugin> </plugins> </build> <!-- 內部開發版本發布庫,這個必須配置,若不配置中央倉庫的話,發布不了 --> <distributionManagement> <repository> <id>maven-releases</id> <name>maven-releases</name> <url>http://127.0.0.1:8081/repository/maven-releases/</url> </repository> <snapshotRepository> <id>maven-snapshots</id> <name>maven-snapshots</name> <url>http://127.0.0.1:8081/repository/maven-snapshots/</url> </snapshotRepository> </distributionManagement> </project>
assembly-zip-deploy.xml
<?xml version='1.0' encoding='UTF-8'?> <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd"> <id>package</id> <formats> <format>zip</format> </formats> <!-- 該值為false表示 output下面不會有個根目錄,名為 artifactId_version 是直接將 fileSets 中的 文件直接放在output下面,見 maven-assembly-demo-0.0.1-SNAPSHOT-package.zip zip包結構 值為true時,可見 maven-assembly-demo-0.0.1-SNAPSHOT-package-includebasedirectory.zip --> <includeBaseDirectory>false</includeBaseDirectory> <fileSets> <fileSet> <directory>zipDeploy</directory> <outputDirectory>/</outputDirectory> //將zipDeploy 目錄下的文件復制到 maven-assembly-plugin 配置的 output 目錄下 </fileSet> </fileSets> </assembly>
通過以上兩個文件打出來的zip目錄結構如下:

注意:
(a) zip包名字構成為:maven-assembly-plugin 配置的 finalName + assembly-zip-deploy.xml 配置的 id ,若 maven-assembly-plugin 中沒有配置 finalName,則默認 finalName 為 artifactId-version,若想生成的 zip 不包含 assembly-zip-deploy.xml 配置的 id,可以在 maven-assembly-plugin 下配置 <appendAssemblyId>false</appendAssemblyId>。
(b) finalName + assembly-zip-deploy.xml 配置的 id 被包含在 zip 名字中之后,該 id 可以作為 classifier 來使用。
(2) 自己編寫的程序工程依賴 (1) 中通過 maven-assembly-plugin 打出來的 zip 包。
工程目錄結構:

該工程也使用了 maven-assembly-plugin 來進行打包,我們的目標是打包出來的成果物,bin 目錄下要包含 (1) 中zip包中的 consul 二進制文件。
pom.xml
<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> <groupId>com.summer</groupId> <artifactId>maven-dependency-plugin-demo</artifactId> <packaging>pom</packaging> <version>0.0.1-SNAPSHOT</version> <name>maven-dependency-plugin-demo</name> <description>demo for maven-dependency-plugin</description> <dependencies> <dependency> <groupId>com.summer</groupId> <artifactId>maven-assembly-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <classifier>package</classifier> <type>zip</type> //依賴 zip 包 </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.8</version> <executions> <execution> <id>unpack</id> <phase>package</phase> <goals> <goal>unpack</goal> </goals> <configuration> //打包階段將依賴的zip解壓到指定的 bin 目錄下 <artifactItems> <artifactItem> <groupId>com.summer</groupId> <artifactId>maven-assembly-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <classifier>package</classifier> <type>zip</type> <outputDirectory>${project.basedir}/bin</outputDirectory> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <id>assembly-package</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> <configuration> <descriptors> <descriptor>assembly-unpack-zip-deploy.xml</descriptor> </descriptors> <outputDirectory>output</outputDirectory> </configuration> </plugin> </plugins> </build> <!-- 內部開發版本發布庫,這個必須配置,若不配置中央倉庫的話,發布不了 --> <distributionManagement> <repository> <id>maven-releases</id> <name>maven-releases</name> <url>http://127.0.0.1:8081/repository/maven-releases/</url> </repository> <snapshotRepository> <id>maven-snapshots</id> <name>maven-snapshots</name> <url>http://127.0.0.1:8081/repository/maven-snapshots/</url> </snapshotRepository> </distributionManagement> </project>
assembly-unpack-zip-deploy.xml
<?xml version='1.0' encoding='UTF-8'?> <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd"> <id>package</id> <formats> <format>zip</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <fileSets> <fileSet> <directory>${project.basedir}</directory> <outputDirectory>/</outputDirectory> <includes> <include>bin/**</include> <include>config/**</include> </includes> </fileSet> </fileSets> </assembly>
以上打出來的zip包結構為:

三、知識點說明
官網敘述地址:http://maven.apache.org/ref/3.6.3/maven-model/maven.html#class_dependency
1、精確匹配依賴某個構件(可以是從一個pom生成的多個成果物,如:log4j-to-slf4j-2.11.2.jar、log4j-to-slf4j-2.11.2-javadoc.jar、log4j-to-slf4j-2.11.2-sources.jar)
<dependency> 表示依賴一個構件,通過 <dependency> 的多個子屬性精確匹配到某個構件,一個構件組成結構為:artifactid-version-classifier.type,如:上述例子 一下的(1) 生成的成果物為:maven-assembly-demo-0.0.1-SNAPSHOT-package.zip ,此時 artifactid為 assembly-demo,version 為 0.0.1-SNAPSHOT,classifier 為 package,type 為 zip,一般從同一個pom若出多個成果物的話,就是使用 classifier 進行區分的。
一般情況下,我們依賴都是這么些:
<dependency>
<groupId>com.summer</groupId>
<artifactId>maven-assembly-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
默認:classifier為null,type 為 jar,上述表示依賴 maven-assembly-demo-0.0.1-SNAPSHOT.jar 包。官網提供了支持的type類型的范圍,但是經過上面的例子感覺 type 不在該范圍也是可以的,比如:zip

官網對這幾個屬性的解釋為:

2、直接依賴的 jar包可以選擇性的傳遞給依賴當前程序的程序
如: A 直接依賴 B(A pom 使用 dependency 標簽直接依賴 B),現在 C 直接依賴 A,若A已經決定 B是否要被C間接依賴 ,可以使用 optional
A.pom
<dependency>
<groupId>xxx</groupId>
<artifactId>B</artifactId>
<version>0.0.1-SNAPSHOT</version>
<optional>true</optional> //表示 依賴A的程序必須自己聲明依賴B,否則B的包不會被程序間接依賴到
</dependency>
C.pom
<dependency>
<groupId>xxx</groupId>
<artifactId>A</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
此時C的依賴列表里面不會有 B
<dependency>
<groupId>xxx</groupId>
<artifactId>A</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>xxx</groupId>
<artifactId>B</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
此時C的依賴列表里面既有A也有B。
PS:
對於這種用法還需謹慎,一般A程序依賴B說明A的功能是需要B程序的,C使用A的功能很有可能也要B。這種用法一般在 Spring 里面看到過,它會使用 @ConditionOnClass(xxx.class)來決定注解該注解的類是否需要執行。
