1. 程式人生 > >恕我直言!!!對於Maven,菜鳥玩dependency,神仙玩plugin

恕我直言!!!對於Maven,菜鳥玩dependency,神仙玩plugin

打包是一項神聖、而莊嚴的工作。package意味著我們離生產已經非常近了。它會把我們之前的大量工作濃縮成為一個、或者多個檔案。接下來,運維的同學就可以拿著這些個打包檔案在生產上縱橫四海了。 這麼一項莊嚴、神聖的工作,卻沒有受到多數人的關注,大家習慣去網上隨意copy一段pom的xml程式碼,往自己專案裡面一扔,然後就開始執行package打包了。大多數只知道,Maven幫助我管理了JAR包的依賴,可以自動下載,很方便。確實,因為它太方便了,很多時候,我們幾乎是沒有感知它的存在。想起來某個功能的時候,直接去使用就可以了。 而構建的工作其實並不簡單!例如: * 打包後的程式,與生產環境JAR包衝突 * 依賴中有多個版本的依賴,如何選擇、排除依賴 * 編譯scala,某些JAR包的呼叫存在相容問題 * 如何根據不同的環境來載入不同的配置,例如:本地環境、叢集環境。 * 編譯開源專案報錯,根本無從下手解決。 * ... 其實,稍微離生產環境近一些,我們會發現很多的問題都暴露了出來。碰到這些問題的時候,當然可以第一時間百度。但為了能夠更精準的定位問題、減少打包時候給別人挖坑,我們還是很有必要來了解一些關於Maven的細節。 # 目錄 [TOC] ## 菜鳥玩dependency,神仙玩plugin 我們使用Maven的時候,95%的時候關注是dependency,而很少有人真正會花時間去研究Maven的plugin。但小猴要告訴大家,其實Maven工作的核心是plugin,而不是dependency。好吧!再直接一點,菜鳥玩dependency,神仙玩plugin。是不是拼命想要反駁我,大家看看官網Plugin在Maven文件的位置,這意味著什麼? 靈魂拷問:大家留意過嗎?是不是隻去官網上下載Maven,然後隨便百度一個教程就開始用Maven了? ![image-20210206120452130](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206120452.png) ## 分析Hadoop Example模組打包 學習的一種最好方式就是借鑑,借鑑優秀的開源專案。看看別人是怎麼做的。所以,接下來,我們就來看看Hadoop是如何打包的。為了方便給大家演示,小猴特意用Maven給大家演示一遍編譯、打包。這樣效果會明顯些。 操作步驟: 1. 在github上找到Apahce/hadoop專案(https://github.com/apache/hadoop) 2. 找到hadoop-mapreduce-project / hadoop-mapreduce-examples模組。 3. 開啟pom.xml檔案。 ```xml ``` 通過瀏覽hadoop example的xml檔案,我們發現了以下幾點: 1. 所有的依賴都在父工程hadoop-project的pom.xml中定義好了。在hadoop example專案中,沒有出現任何一個版本號。 ![image-20210206104307402](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206104307.png) 2. Hadoop使用了三個外掛,一個是maven-jar-plugin、一個是findbugs-maven-plugin、還有一個是apache-rat-plugin。 我們進入到example模組中pom.xml所在的目錄中,直接執行mvn package試試看。 ```shell [root@compile hadoop-mapreduce-examples]# mvn package [INFO] Scanning for projects... [INFO] [INFO] ------------< org.apache.hadoop:hadoop-mapreduce-examples >------------- [INFO] Building Apache Hadoop MapReduce Examples 3.2.1 [INFO] --------------------------------[ jar ]--------------------------------- Downloading from apache.snapshots.https: https://repository.apache.org/content/repositories/snapshots/org/apache/hadoop/hadoop-mapreduce-client-app/3.2.1/hadoop-mapreduce-client-app-3.2.1-tests.jar ..... [INFO] [INFO] --- maven-antrun-plugin:1.7:run (create-testdirs) @ hadoop-mapreduce-examples --- [INFO] Executing tasks main: [INFO] Executed tasks [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hadoop-mapreduce-examples --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /opt/hadoop-3.2.1-src/hadoop-mapreduce-project/hadoop-mapreduce-examples/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hadoop-mapreduce-examples --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hadoop-mapreduce-examples --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /opt/hadoop-3.2.1-src/hadoop-mapreduce-project/hadoop-mapreduce-examples/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hadoop-mapreduce-examples --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-surefire-plugin:3.0.0-M1:test (default-test) @ hadoop-mapreduce-examples --- Downloading from central: http://maven.aliyun.com/nexus/content/groups/public/org/apache/maven/surefire/surefire-junit4/3.0.0-M1/surefire-junit4-3.0.0-M1.jar .......... [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running org.apache.hadoop.examples.TestBaileyBorweinPlouffe [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.536 s - in org.apache.hadoop.examples.TestBaileyBorweinPlouffe .......... [INFO] [INFO] Results: [INFO] [INFO] Tests run: 11, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- maven-jar-plugin:2.5:jar (default-jar) @ hadoop-mapreduce-examples --- [INFO] [INFO] --- maven-site-plugin:3.6:attach-descriptor (attach-descriptor) @ hadoop-mapreduce-examples --- [INFO] Skipping because packaging 'jar' is not pom. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 01:11 min [INFO] Finished at: 2021-02-06T10:49:18+08:00 [INFO] ------------------------------------------------------------------------ ``` 很快就編譯成功了,我們來看看Maven做了什麼: 1、執行maven-antrun-plugin外掛的run create-testdirs任務。奇怪的是,Example模組中並沒有引入該外掛。一會來看看該外掛在何處配置的。 ```shell [INFO] --- maven-antrun-plugin:1.7:run (create-testdirs) @ hadoop-mapreduce-examples --- [INFO] Executing tasks ``` 2、執行maven-resources-plugin外掛的resources任務,這個外掛應該是拷貝resource目錄到target的。 ```shell [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hadoop-mapreduce-examples --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /opt/hadoop-3.2.1-src/hadoop-mapreduce-project/hadoop-mapreduce-examples/src/main/resources ``` 3、執行maven-compiler-plugin外掛的compile任務,注意:現在才開始編譯程式碼。因為發現我們之前已經編譯過了,所以此處並沒有重新編譯class。 ```shell [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hadoop-mapreduce-examples --- [INFO] Compiling 47 source files to /opt/hadoop-3.2.1-src/hadoop-mapreduce-project/hadoop-mapreduce-examples/target/classes ``` 4、執行maven-resources-plugin外掛的testResources任務,顧名思義,就是將單元測試相關的resource目錄拷貝到target。 ```shell [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hadoop-mapreduce-examples --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /opt/hadoop-3.2.1-src/hadoop-mapreduce-project/hadoop-mapreduce-examples/src/test/resources ``` 5、執行maven-compiler-plugin外掛的testCompile任務,同樣,將單元測試的檔案編譯一遍。 ```shell [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hadoop-mapreduce-examples --- [INFO] Compiling 7 source files to /opt/hadoop-3.2.1-src/hadoop-mapreduce-project/hadoop-mapreduce-examples/target/test-classes ``` 6、執行maven-surefire-plugin外掛的test任務,開始執行單元測試。確保編譯的程式碼沒有問題。 ```shell INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running org.apache.hadoop.examples.TestBaileyBorweinPlouffe [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.436 s - in org.apache.hadoop.examples.TestBaileyBorweinPlouffe [INFO] Running org.apache.hadoop.examples.TestWordStats [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.332 s - in org.apache.hadoop.examples.TestWordStats [INFO] Running org.apache.hadoop.examples.pi.math.TestLongLong [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.163 s - in org.apache.hadoop.examples.pi.math.TestLongLong [INFO] Running org.apache.hadoop.examples.pi.math.TestModular [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.164 s - in org.apache.hadoop.examples.pi.math.TestModular [INFO] Running org.apache.hadoop.examples.pi.math.TestSummation [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.091 s - in org.apache.hadoop.examples.pi.math.TestSummation [INFO] Running org.apache.hadoop.examples.terasort.TestTeraSort [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.449 s - in org.apache.hadoop.examples.terasort.TestTeraSort ``` 7、執行maven-jar-plugin外掛的jar任務,這個任務是打包成jar檔案。 ```shell [INFO] --- maven-jar-plugin:2.5:jar (default-jar) @ hadoop-mapreduce-examples --- [INFO] Building jar: /opt/hadoop-3.2.1-src/hadoop-mapreduce-project/hadoop-mapreduce-examples/target/hadoop-mapreduce-examples-3.2.1.jar ``` 8、執行maven-site-plugin的attach-descriptor任務。該任務只有專案是pom打包時候才可用,將site.xml(site描述符)新增到部署的檔案列表中。 ```shell [INFO] --- maven-site-plugin:3.6:attach-descriptor (attach-descriptor) @ hadoop-mapreduce-examples --- [INFO] Skipping because packaging 'jar' is not pom. ``` 由此,我們可以發現,當我們執行一個package、compile、或者clean命令時,其實背後都是執行Maven的一個外掛。只不過有的外掛是Maven自帶的,直接可以使用,當我們需要自定義外掛的行為時,就需要顯示在pom.xml中顯式配置外掛了。 Maven中有大量的、豐富的外掛供開發人員使用。 ![image-20210206110859445](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206110859.png) 地址:https://maven.apache.org/plugins/ 我們可以點選任意一個plugin,檢視其具體的內容。 ![image-20210206111024621](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206111024.png) ### maven-antrun-plugin外掛 我們發現在example模組的父模組hadoop-project中有一個pom.xml。 ```xml ``` 我們看到這裡面有配置一些外掛,其中就個maven-antrun-plugin。該外掛會執行run#create-testdirs任務,並且在validate階段執行。我們看到,該外掛執行了兩次mkdir。 ### maven-jar-plugin外掛 外掛配置如下: ```xml ``` 前面,我們看到了是在執行package階段時自動執行的。並且指定了執行的主類是ExampleDriver。通過檢視打包後的JAR檔案,我們可以發現,JAR外掛只會將專案中的class檔案打包到JAR檔案中,並不會打包其他的依賴。 ![image-20210206114017839](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206114017.png) 並且,在JAR包的META-INF(元資料中),可以看到MAINFEST.MF檔案,已經生成了執行主類: ![image-20210206114118518](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206114118.png) 這個外掛的相關說明,可以參看官網:https://maven.apache.org/plugins/maven-jar-plugin/ ## JAR包中的META-INF目錄 在每個jar包中有一個META-INF目錄,顧名思義。它肯定是包含了JAR檔案的元資料相關。Java基於META-INF目錄中的檔案來配置Java應用程式、類載入器以及其他服務。它包含以下內容: ### MANIFEST.MF 用於定義副檔名以及打包相關的清單。 ```properties Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Built-By: China Created-By: Apache Maven 3.5.0 Build-Jdk: 1.8.0_241 Main-Class: cn.monkey.StreamingJob ``` 該檔案中顯示了檔案的版本、由哪個使用者構建的、由哪個應用建立的、構建的JDK版本、以及非常重要的Main-Class。 ### INDEX.LIST 該檔案由JAR工具的-i選項生成,包括了應用程式或者擴充套件中定義的包的位置。用於類載入器加速類載入過程。 ### xxx.SF JAR包的簽名檔案 ### xxx.DSA 與SF檔案關聯的簽名塊檔案。該檔案儲存了簽名檔案對應的數字簽名。 ## Maven外掛 ### Maven構建生命週期 Maven是一個專案管理工具,它把專案的構建主要分為了以下階段: * validate:驗證專案是否正確,所有必要的資訊是否均已經提供 * compile:編譯專案的原始碼。 * test:執行單元測試。 * package:打包已編譯的程式碼。 * verify:對整合測試結果進行檢查,確保符合質量標準。 * install:將軟體包安裝到本地倉庫。 * deploy:將最終的軟體包複製到遠端倉庫,方便和其他開發人員共享。 也就是說,只要是一個Maven專案,從原始碼到一個可執行的程式,需要經歷著一系列的構建階段。而每個階段的背後,是Maven提供了一個構建過程的核心執行引擎,這個核心的專案構建執行引擎是由大量的外掛來執行具體的任務。 ### 重新定義Maven 讓我們從技術角度,重新定義Maven——一個包含了很多外掛的框架。真正執行各種Maven操作的其實都是外掛。例如: * 構建JAR包 * 構建WAR包 * 編譯程式碼 * 執行單元測試 * 建立專案文件 等等。只要是能夠想到需要在專案上執行的所有操作,其背後都是外掛實現的。 外掛是Maven的核心功能,一旦定義好了外掛,就可以在多個專案中重用。想想,我們是不是在每個pom.xml配置打包外掛、編譯外掛等等。找到pom.xml的位置,然後執行 package、comile、clean等操作即可。當我們執行: ```shell mvn compile ``` 的時候,Maven得知道,哦!當前要執行編譯了。由此可以知道,Maven的外掛是由mvn的引數來驅動的。這些引數定義了外掛的目標(或者Mojo)。 ### Mojo Maven中最簡單的外掛是Clean Plugin。它只是負責刪除Maven專案的target目錄。但執行`mvn clean`時,Maven將執行Clean外掛中定義的clean目標(Goal),並刪除目標目錄。Clean外掛還定義了可用於自定義外掛行為的引數,長概述為outputDirectory,預設為${project.build.directory}。 Mojo實際上是Maven外掛中的一個目標(Goal),一個外掛可以包含許多的Goal。我們可以用帶註解的Java類或者BeanShell指令碼來定義Mojo。它指定了Goal相關的元資料:Goal名稱、以及Goal所執行的生命週期、以及引數。 ### 檢視clean外掛原始碼 通過Maven官網的plugins連結,我們可以找到clean外掛在github的地址。 ![image-20210206124814385](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206124814.png) ![image-20210206124929870](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206124929.png) 看到src目錄和pom.xml,我們就可以知道,原來Maven的plugin也是一個Maven標準專案。先來看看pom.xml裡面有什麼。為了方便觀察,我刪除了一些程式碼。 ```xml ``` 我們看到,pom.xml中引入了一些必要的依賴、以及定義了一些其他外掛的版本、在profile中,還定義了maven-invoker-plugin的配置。裡面配置了 > Invoker外掛:用於執行一組Maven專案,該外掛可以確定每個專案執行是否成功,並且可以選擇驗證從給定專案執行生成的輸出。比較適合用於整合測試。 ![image-20210206130007340](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206130007.png) 我們看到了原始碼中有一個CleanMojo的原始檔,程式碼中使用了註解來定義外掛的Goal和引數。 ![image-20210206130107577](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206130107.png) ![image-20210206130431392](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206130431.png) 我們看到execute中就是執行clean目標,裡面呼叫了Cleaner來清理檔案。再檢視下install外掛的Mojo ![image-20210206130701348](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206130701.png) install預設繫結的是INSTALL階段。 看完上面的原始碼,我們知道:以後使用外掛,可以看看它的Mojo檔案就知道它對應的目標是什麼、引數是什麼。我們還可以通過外掛的原始碼來進行錯誤排查。 ## 分析Flink Archetype中的pom.xml scala版本的pom.xml依賴要比Java版本要複雜,因為Maven預設就是用於構建Java的。而針對scala的構建,需要進行額外配置Maven支援。 ```shell mvn archetype:generate \ -DarchetypeGroupId=org.apache.flink \ -DarchetypeArtifactId=flink-quickstart-scala \ -DarchetypeVersion=1.12.1 ``` Flink自動生成的程式碼如下: ```xml ``` 這是一個標準Flink Maven腳手架,Flink清晰地告訴了我們,哪些依賴是需要設定為provided、哪些是runtime,如果需要使用connector,需要自己額外引入對應不同儲存庫的connector。我們重點來分析外掛: * maven-shade-plugin:可以看到,Flink是使用shade外掛進行fat jar打包的。可以通過mainClass引數配置jar包的入口。 * maven-compiler-plugin:配置Java編譯器。Flink預設使用1.8進行編譯。 * scala-maven-plugin:配置Scala編譯器。 * maven-eclipse-plugin:該外掛定義了編譯scala和java檔案 我們重點來看shade外掛。 > 注意: > > 如果多個外掛配置的生命週期階段為package,那麼會按照pom.xml的順序依次執行。 ## Shade外掛 ```xml ``` Shade外掛可以將打包所有的artifact到一個uber-jar(uber-jar表示在一個JAR檔案中包含自身、以及所有的依賴)。Shade外掛只有一個goal:shade:shade。 Mojo原始碼URL:https://github.com/apache/maven-shade-plugin/blob/master/src/main/java/org/apache/maven/plugins/shade/mojo/ShadeMojo.java ![image-20210206143601564](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206143601.png) 可以看到,該外掛的生命週期配置在package,也就是執行package時,會自動執行。 在configuration中配置了要排除哪些artifacts。filter中配置了排除所有JAR包中的簽名檔案。我們可以在artifactSet、filter中來解決包衝突問題。 ## Assembly外掛 ### 簡介 很多時候我們需要把專案打包成一個tar.gz包,就像Apache的一些元件一樣。通過使用Assembly外掛可以將程式、文件、配置檔案等等打包成一個“assemblies”。使用一個assembly descriptor可以描述整個過程。使用該外掛,可以把應用打包成以下型別: ```xml zip tar tar.gz (or tgz) tar.bz2 (or tbz2) tar.snappy tar.xz (or txz) jar dir war ``` 而如果要打包成user-jar,assembly外掛提供了一些基本的支援。官方建議還是使用shade外掛。Assembly外掛的使用步驟如下: 1. 選擇或編寫一個assembly descriptor 2. 在pom.xml檔案中配置assembly外掛 3. 執行mvn assembly:single ### Assembly介紹 Assembly(程式集)指的是一組檔案、目錄以及相關的依賴,為了方便軟體的安裝、部署、以及分發,我們可以把Assembly組織成一個zip包、或者tar.gz這種型別的包。例如:一個Maven專案中包含了控制檯應用和FX桌面客戶端應用。可以定義兩個Assembly,將應用和不同的指令碼、依賴繫結到一起。 針對Assembly,需要有一個Assembly Descriptor(程式集描述符),通過assembly descripor檔案可以描述將哪些檔案複製到bin目錄,並且可以修改目錄中檔案的許可權。 ### Goal 每一個Maven外掛都會有一個Goal,Assembly外掛也有一個Goal,那就是single,表示建立所有的Assembly。 ### 分析Hadoop專案的Assembly外掛 #### Maven外掛配置 我們來看一下Hadoop中如何使用該外掛的。 ```xml ``` 解釋下每個XML節點的意義: | 配置項 | 說明 | | ---------------- | ------------------------------------------------------------ | | appendAssemblyId | 設定為false表示從最終的輸出程式集中排除src-dist名字 | | attach | 控制Assembly外掛是否將生成的assembly附加到專案中 | | finalName | Assembly發行版最終的檔名 | | outputDirectory | Assembly檔案的最終輸出目錄 | | descriptors | 預設會從bin、jar-with-dependencies、src、project中載入內建描述符。 | 內建的descriptors可以從assembly.jar中載入。 ![image-20210206183715685](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206183715.png) 可以參考https://maven.apache.org/plugins/maven-assembly-plugin/descriptor-refs.html看到所有內建的descriptor中說明。這裡Hadoop配置的是自己的descriptor。 > 大家可以參考外掛的AbstractAssemblyMojo.java中的定義。 #### hadoop-src.xml Assembly配置 ```xml ``` 我們可以參考:https://maven.apache.org/plugins/maven-assembly-plugin/assembly.html看到assembly相關的所有配置。 | 配置項 | 配置 | 說明 | | -------------------------- | ------------ | ------------------------------------------------------------ | | id | hadoop-src | 設定Assembly的id。 | | formats/format* | tar.gz | 指定assembly的最終格式。這裡hadoop配置的是tar.gz,表示最終打包出來一個tar.gz檔案,當然可以配置多個。例如:zip、tar、jar等。 | | includeBaseDirectory | true | 在tar.gz中包括一個base目錄。就是tar.gz會包含一個資料夾。而不是直接把大量的檔案直接放在tar.gz中。(這個一定要配置true,不然解壓安裝的時候會很蛋疼。) | | fileSets | fileset | 指定要包含在Assembly中的模組檔案。就是最終要將哪些檔案複製到tar.gz中。 | | fileset/useDefaultExcludes | true | 是否應使用標準排除模式。對於向後相容性,預設值為true。 | | fileset/directory | . | 設定模組目錄中的絕對或相對位置。例如,“src/main/bin”將選擇定義此依賴項的專案的子目錄。該目錄配置表示要打包哪個目錄下的檔案。 | | includes/include* | LICENCE.txt | 定義一組要包含的檔案和目錄。如果沒有配置,表示所有target內容 | | excludes/exclude* | **/.settings | 定義一組要排除的檔案和目錄。 | ## 製作一個屬於我們自己的打包程式 ### 需求 我們通過編寫一個簡單的程式碼,然後將程式碼打包成類似於Apache的軟體包。程式碼非常簡單: ```java public class HelloMaven { public static void main(String[] args) { System.out.println("Hello! Maven Assembly Plugin!"); } } ``` 有一個配置檔案,我們也需要打包: ```properties version=1.1.0 ``` ![image-20210206210951618](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206210951.png) ### 新增一個測試依賴 在pom.xml中新增以下: ```xml ``` 一會我們會用shade外掛,將該依賴直接打成uber-jar。 ### 配置shade外掛 ```xml ``` 執行package時,會先執行maven-jar-plugin。然後就會執行shade外掛了。注意:因為我們一會要使用assembly打包,將shade打包的user-jar直接打進tar.gz。所以,shade要配置在assembly外掛之前。 > 注意配置mainClass,也就是JAR的執行主類 ### 配置Assembly外掛 #### 配置Maven pom.xml ```xml ``` * finalName為最終打包的檔名,此處為artifactId加上bin字尾 * outputDirectory配置為Maven預設的輸出目錄,也就是一會打包完會自動在target目錄生成tar.gz #### 配置assembly descriptor ```xml ``` * 我們最終的檔案以tar.gz方式打包 * 第一個fileset為打包lib,我們最終的程式以jar包形式存放在tar.gz的lib資料夾中 * 第二個fileset打包配置檔案,這裡直接打包config.properties * 第三個fileset打包執行的shell指令碼,並且配置了755可執行許可權 ### 建立執行指令碼 在main目錄中新增shell-scripts/start.sh,要執行程式直接執行start.sh即可 ```shell #!/bin/bash java -jar lib/${artifact.name} ``` ### 配置資源打包 ```xml ``` 我們需要對shell-scriptrs下的指令碼進行變數替換。 ### 配置profile ```xml ``` 此處配置預設的Profile為pro,當打包時會用artifact.name屬性直接對shell-script中的指令碼進行替換。 ### 執行打包 我把Maven的執行過程給大家解析一遍。 ```xml # 注意此處自動指定了profile為pro C:\opt\jdk1.8.0_241\bin\java.exe -Dmaven.multiModuleProjectDirectory=C:\Users\China\Desktop\assembly-test -Dmaven.multiModuleProjectDirectory=$MAVEN_HOME -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true -Dmaven.home=C:\Java\apache-maven-3.5.0 -Dclassworlds.conf=C:\Java\apache-maven-3.5.0\bin\m2.conf "-Dmaven.ext.class.path=C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.2\plugins\maven\lib\maven-event-listener.jar" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.2\lib\idea_rt.jar=58840:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.2\bin" -Dfile.encoding=UTF-8 -classpath C:\Java\apache-maven-3.5.0\boot\plexus-classworlds-2.5.2.jar org.codehaus.classworlds.Launcher -Didea.version=2020.3.2 package -P pro [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building assembly-test 1.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] # 拷貝resoource資原始檔 [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ assembly-test --- [WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent! [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] Copying 1 resource [INFO] Copying 1 resource to C:\Users\China\Desktop\assembly-test\target\classes/shell-scripts [INFO] # 執行編譯外掛 [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ assembly-test --- [INFO] Nothing to compile - all classes are up to date [INFO] # 執行test資源拷貝,當前為空 [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ assembly-test --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory C:\Users\China\Desktop\assembly-test\src\test\resources [INFO] # 執行編譯測試用例程式碼 [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ assembly-test --- [INFO] Nothing to compile - all classes are up to date [INFO] # 執行單元測試 [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ assembly-test --- [INFO] No tests to run. [INFO] # 執行Maven的預設jar打包 [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ assembly-test --- [INFO] Building jar: C:\Users\China\Desktop\assembly-test\target\assembly-test-1.0-SNAPSHOT.jar [INFO] # 執行shade外掛打包 [INFO] --- maven-shade-plugin:3.1.1:shade (default) @ assembly-test --- [INFO] Including commons-cli:commons-cli:jar:1.2 in the shaded jar. [INFO] Replacing original artifact with shaded artifact. [INFO] Replacing C:\Users\China\Desktop\assembly-test\target\assembly-test-1.0-SNAPSHOT.jar with C:\Users\China\Desktop\assembly-test\target\assembly-test-1.0-SNAPSHOT-shaded.jar [INFO] Dependency-reduced POM written at: C:\Users\China\Desktop\assembly-test\dependency-reduced-pom.xml [INFO] # 執行assembly外掛打包 [INFO] --- maven-assembly-plugin:2.2-beta-5:single (assembly-test) @ assembly-test --- [INFO] Reading assembly descriptor: test-assemblies/test-descriptor.xml [INFO] Building tar : C:\Users\China\Desktop\assembly-test\target\assembly-test-bin.tar.gz [WARNING] Assembly file: C:\Users\China\Desktop\assembly-test\target\assembly-test-bin.tar.gz is not a regular file (it may be a directory). It cannot be attached to the project build for installation or deployment. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.202 s [INFO] Finished at: 2021-02-06T21:19:21+08:00 [INFO] Final Memory: 15M/491M [INFO] ------------------------------------------------------------------------ Process finished with exit code 0 ``` 是不是一目瞭然? 一頓操作後,我們發現確實打包成了tar.gz了。 ![image-20210206212226277](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206212226.png) 用壓縮軟體開啟看一下: ![image-20210206212250495](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206212250.png) 全部都已經打包好了。而且shell指令碼已經進行了變數替換。 ![](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206212250.png) ### 在Linux上部署 ```shell # 上傳到Linux伺服器 [root@compile assembly-test]# ll 總用量 40 -rw-r--r--. 1 root root 39611 2月 6 21:19 assembly-test-bin.tar.gz # 解壓 [root@compile assembly-test]# tar -xvzf assembly-test-bin.tar.gz assembly-test-bin/lib/assembly-test-1.0-SNAPSHOT-shaded.jar assembly-test-bin/conf/config.properties assembly-test-bin/bin/start.sh # 執行 [root@compile assembly-test-bin]# pwd /root/assembly-test/assembly-test-bin [root@compile assembly-test-bin]# bin/start.sh Hello! Maven Assembly Plugin! ``` 是不是很酷~這樣的程式才是真正的、很正式的程式。 ### 打包原始碼 最後為了方便小夥伴們測試,我們把Maven專案的原始碼打包一份。還是使用assembly外掛。 #### 在Assembly中建立一個新的execution ```xml ``` 注意:我當前配置的phase為compile,也就是編譯階段就會打包好maven的原始碼. #### 為打包原始碼配置assembly descriptor ```xml ``` 此處j將src原始碼目錄、test-assemblies下的所有檔案、以及pom.xml一塊打包給小夥伴。 #### 執行compile ```shell [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building assembly-test 1.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ assembly-test --- [WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent! [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] Copying 1 resource [INFO] Copying 1 resource to C:\Users\China\Desktop\assembly-test\target\classes/shell-scripts [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ assembly-test --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-assembly-plugin:2.2-beta-5:single (test-source-descriptor) @ assembly-test --- [INFO] Reading assembly descriptor: test-assemblies/test-source-descriptor.xml [INFO] Building zip: C:\Users\China\Desktop\assembly-test\target\assembly-test-source.zip [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.274 s [INFO] Finished at: 2021-02-06T21:38:37+08:00 [INFO] Final Memory: 13M/491M [INFO] ------------------------------------------------------------------------ Process finished with exit code 0 ``` 大家看到assembly外掛已經執行,並將程式碼打包好了。 ![image-20210206214137329](https://pick-bed2021.oss-cn-beijing.aliyuncs.com/img/2021Q1/20210206214137.png) 大家看到了,這才是我們做為一個開發應該玩的Maven。本次的案例程式碼在我公眾號上回復:maven-plugin即可獲取下載連結。大家自取之。 我們下期再見! 以上 參考文獻 > [1] https://maven.apache.org/plugins/ > > [2] https://github.com/apache/hadoop > > [3] https://maven.apache.org/guides/introduction/introduction-to-plugins.html > > [4] https://github.com/apache/spark > > [5] https://stackoverflow.com/questions/11947037/what-is-an-uber-jar > > [6] https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html > > [7] https://maven.apache.org/plugins/maven-assembly-plugin/index.html > > [8] https://github.com/cko/predefined_maven_properties/blob/master/README.md