【Maven從入門到精通】 01-自動化構建工具:Maven
目錄
自動化構建工具:Maven
目前掌握的技術
目前技術在開發中存在的問題
-
一個專案就是一個工程
- 產生的問題:專案非常龐大時,就不適合使用 package 劃分模組。最好是一個模組對應一個工程,這樣利於分工協作
- 藉助 Maven
-
專案所需 Jar 包需要手動複製貼上至
WEB-INF/lib
下- 產生的問題:同樣的 Jar 包重複出現在不同的專案工程中,一來佔用儲存空間,二來顯得臃腫
- 藉助 Maven:可以將 Jar 儲存在 倉庫 中,需使用的專案工程中只需 引用 即可,無需真正地複製 Jar 包
-
Jar 包需要別人替我們準備好,或是官網下載
- 產生的問題:不同技術的官網提供 Jar 包下載的形式是五花八門的,有些官網就是通過 Maven 或 SVN 等專門的工具提供下載的。如果下載的 Jar 包 來路不正 ,那麼很可能其中的內容也是不正規的
- 藉助 Maven:可以以規範的方式下載 Jar 包。因為所有知名框架或是第三方工具的 Jar 包已經按照統一規範存放在了 Maven 的中央倉庫中,其內容也是可靠的
- Tips:統一規範不僅對於 IT 開發領域非常之重要,對於整個人類社會也是非常之重要
-
一個 Jar 包所依賴的其他 Jar 包需要手動加入專案中
-
產生的問題:如果所有的 Jar 包依賴關係都需要程式設計師自己瞭解的特別清楚,就會極大地增加學習和開發成本
-
藉助 Maven:自動將 Jar 包所需的依賴包匯入進來
FileUpload 元件 → IO 元件;commons-fileupload-1.3.jar 依賴於 commons-io-2.0.1.jar
-
1、Maven 到底是啥?
-
概念:Maven 是 Java 平臺上的自動化構建工具(Maven 本身也是使用 Java 編寫的)
-
構建工具發展歷程:
Make
➡️Ant
➡️Maven
➡️Gradle
2、什麼是構建?
以 Java 原始檔、框架配置檔案、HTML/CSS/JS/JSP、圖片等資源為 原材料,去 生產 一個可以執行的工程專案的過程
- 編譯:Java 原始檔 ➡️ 編譯 ➡️ Class 位元組碼檔案
- 部署:一個 BS 專案最終執行的並不是動態 Web 工程本身,而是動態 Web 工程編譯 後的結果
要深入地理解構建的含義,可以從以下三個層面來看:
-
純 Java 程式碼
大家都知道,我們Java是一門編譯型語言,
.java
副檔名的原始檔需要編譯成.class
副檔名的位元組碼檔案才能夠執行。所以編寫任何 Java 程式碼想要執行的話就必須經過編譯得到對應的.class
檔案 -
Web 工程
當我們需要通過瀏覽器訪問 Java 程式時就必須將包含 Java 程式的 Web 工程編譯的結果 拿 到伺服器上的指定目錄,並啟動伺服器才行。這個 拿 的過程我們叫部署。我們可以將未編譯的 Web 工程比喻為一隻生的雞,編譯好的 Web 工程是一隻煮熟的雞,編譯部署的過程就是將雞燉熟。即:動態 Web 工程 ➡️ 編譯、部署 ➡️ 編譯結果 <=> 生雞 ➡️ 煮熟 ➡️ 熟雞
Web 工程和其編譯結果的目錄結構對比見下圖
開發過程中,所有的路徑或配置檔案中的類路徑都是以編譯結果的目錄結構為標準的
Tips:執行時環境
其實是一組 jar 包的引用,並沒有把 jar 包本身複製到工程中,所以並不是目錄
-
實際專案
在實際專案中整合第三方框架, Web 工程中除了 Java 程式和 JSP 頁面、圖片等靜態資源之外,還包括第三方框架的 jar 包以及各種各樣的配置檔案。所有這些資源都必須按照正確的目錄結構部署到伺服器上,專案才可以執行
所以綜上所述:構建就是以我們編寫的 Java 程式碼、框架配置檔案、國際化等其他資原始檔、JSP 頁面和圖片等靜態資源作為 原材料,去 生產 出一個可以執行的專案的過程
3、構建過程中的各個環節
- 1️⃣ 清理:講之前編譯得到的舊的
.class
位元組碼檔案刪除,為下一次編譯做準備 - 2️⃣ 編譯:將 Java 源程式編譯成 Class 位元組碼檔案
- 3️⃣ 測試:自動測試,呼叫 Junit 程式
- 4️⃣ 報告:測試程式執行的結果
- 5️⃣ 打包:動態 Web 工程打成 War 包,Java 工程打成 Jar 包
- 6️⃣ 安裝:講打包得到的檔案 複製 到 倉庫 中的特定位置
- 7️⃣ 部署:將動態 Web 工程生成的 War 包 複製 到 Servlet 容器中的指定目錄下,使其可以執行
4、自動化構建
其實上述環節我們在 Eclipse 中都可以找到對應的操作,只是不太標準。那麼既然 IDE 已經可以進行構建了我們為什麼還要使用 Maven 這樣的構建工具呢?我們來看一個小故事:
這是陽光明媚的一天。托馬斯嚮往常一樣早早的來到了公司,衝好一杯咖啡,進入了自己的郵箱——很不幸,QA 小組發來了一封郵件,報告了他昨天提交的模組的測試結果——有BUG。
“好吧,反正也不是第一次”,托馬斯搖搖頭,進入 IDE,執行自己的程式,編譯、打包、部署到伺服器上,然後按照郵件中的操作路徑進行測試。
“嗯,沒錯,這個地方確實有問題”,托馬斯說道。於是托馬斯開始嘗試修復這個BUG,當他差不多有眉目的時候已經到了午飯時間。
下午繼續工作。BUG很快被修正了,接著托馬斯對模組重新進行了編譯、打包、部署,測試之後確認沒有問題了,回覆了QA小組的郵件。
一天就這樣過去了,明媚的陽光化作了美麗的晚霞,托馬斯卻覺得生活並不像晚霞那樣美好啊。
讓我們來梳理一下托馬斯這一天中的工作內容
從中我們發現,托馬斯的很大一部分時間花在了“編譯、打包、部署、測試”這些程式化的工作上面,而真正需要由“人”的智慧實現的分析問題和編碼卻只佔了很少一部分
能否將這些程式化的工作交給機器自動完成呢?——當然可以!這就是自動化構建
此時 Maven 的意義就體現出來了,它可以自動地從構建過程的起點一直執行到終點
5、安裝 Maven 核心程式
-
檢查 JAVA_HOME 環境變數
-
解壓 Maven 核心程式的壓縮包,放在一個非中文無空格路徑下
-
配置 Maven 相關的環境變數
MAVEN_HOME
或M2_HOME
PATH
-
驗證:執行
mvn -v
檢視 Maven 版本
6、Maven 的核心概念
- 1️⃣ 約定的目錄結構
- 2️⃣ POM
- 3️⃣ 座標
- 4️⃣ 依賴
- 5️⃣ 倉庫
- 6️⃣ 生命週期 / 外掛 / 目標
- 7️⃣ 繼承
- 8️⃣ 聚合
7、約定的目錄結構
- 根目錄:工程名
- |—— src 目錄:原始碼
- |—— pom.xml檔案:Maven 工程的核心配置檔案
- |———— main 目錄:存放主程式
- |———————— java 目錄:存放 Java 原始檔
- |———————— resource 目錄:存放框架或其他工具的配置檔案
- |———— test 目錄:存放測試程式
- |———————— java 目錄:存放 Java 測試原始檔
- |———————— resource 目錄:存放框架或其他工具的測試配置檔案
為什麼要遵守約定的目錄結構呢?
- 巧婦難為無米之炊:Maven 要負責我們專案的自動化構建,以編譯為例,Maven 要想自動進行編譯,就必須要知道 Java 原始檔的位置
- 如果想讓框架或工具知道我們自定義的東西,方法有二:
- 以配置的方式指定:如
<param-value>classpath:spring-context.xml</param-value>
- 遵守框架內部約定:如
log4j.properties
/log4j.xml
- 以配置的方式指定:如
- JavaEE 的開發共識:約定 > 配置 > 編碼
8、常見的 Maven 命令
❗ ❗ ❗ 注意:執行與構建過程相關的 Maven 命令,必須進入 pom.xml 所在的目錄
與構建過程相關:編譯、測試、打包、.……
mvn clean
:清理mvn compile
:編譯主程式mvn test-compile
:編譯測試程式mvn test
:執行測試mvn package
:打包
9、關於聯網問題
Maven 核心程式僅僅是定義了抽象的生命週期,但是具體的工作必須要由外掛來完成。而外掛本身並不包含在 Maven 核心程式中
- 執行的 Maven 命令需要用到某些外掛時,Maven 核心程式會首先在本地倉庫中查詢
- 本地倉庫的預設位置:
【系統當前使用者的家目錄】\.m2\repository
(windows:C:\Users\[使用者名稱]\.m2\repository
)
- 本地倉庫的預設位置:
- 修改本地倉庫的預設位置,Maven 核心程式會到我們事先準備好的目錄下查詢外掛
- 開啟
[Maven解壓目錄]\conf\settings.xml
,找到localRepository
標籤,修改目錄
- 開啟
- Maven 核心程式如果在本地倉庫中找不到需要的外掛,會自動到中央倉庫下載。如果此時無法連線外網,則構建失敗
10、第一個 Maven 程式
目錄結構
編寫程式碼
public class Hello {
public String sayHello(String name) {
return "Hello " + name + "!";
}
}
public class HelloTest {
@Test
public void testHello() {
Hello hello = new Hello();
String results = hello.sayHello("world");
assertEquals("Hello world!", results);
}
}
編譯
mvn compile
執行過程
目錄內容:
classes
目錄
測試編譯
mvn test-compile
執行過程
目錄內容:
classes
目錄:主程式編譯後的位元組碼檔案test-classes
目錄:測試程式編譯後的位元組碼檔案
測試
mvn test
執行過程
目錄結構
surefire-reports
:測試報告,本例為com.vectorx.maven.HelloTest.txt
- 測試報告會統計所有測試方法執行的最終結果
本例只有一個測試方法,並且最終執行結果為:執行成功數:1,執行失敗數:0,執行錯誤數:0,跳過:0,總耗時:0.103 秒
,說明本例中testHello
測試方法斷言正確,驗證通過
打包
mvn package
執行過程
目錄內容:
classes
/test-classes
:主程式 / 測試程式編譯的位元組碼檔案surefire-reports
:測試報告Hello-0.0.1-SNAPSHOT.jar
:jar 包檔案maven-archiver
/maven-status
等其他額外檔案
清理
mvn clean
執行過程
目錄內容:
- 清理會清空整個
target
目錄及其內容