概念
什麼是Maven
Maven 是 Apache 軟件基金會組織維護的一款自動化構建工具,專注服務於 Java 平臺的項目構建和依賴管理。Maven 這個單詞的本意是:專家,內行。讀音是[‘meɪv(ə)n]或[‘mevn]。
什麼是構建
構建並不是創建,創建一個工程並不等於構建一個項目。要了解構建的含義我們應該由淺入深的從以下三個層面來看:
純 Java 代碼
大家都知道,我們 Java 是一門編譯型語言,.java 擴展名的源文件需要編譯成.class 擴展名的字節碼文件才能夠執行。所以編寫任何 Java 代碼想要執行的話就必須經過編譯得到對應的.class 文件。
Web 工程
當我們需要通過瀏覽器訪問 Java 程序時就必須將包含 Java 程序的 Web 工程編譯的結果“拿”到服務器上的指定目錄下,並啟動服務器才行。這個“拿”的過程我們叫部署。
我們可以將未編譯的 Web 工程比喻為一隻生的雞,編譯好的 Web 工程是一隻煮熟的雞,編譯部署的過程就是將雞燉熟。
Web 工程和其編譯結果的目錄結構對比見下圖:
實際項目
在實際項目中整合第三方框架,Web 工程中除了 Java 程序和 JSP 頁面、圖片等靜態資源之外,還包括第三方框架的 jar 包以及各種各樣的配置文件。所有這些資源都必須按照正確的目錄結構部署到服務器上,項目才可以運行。所以綜上所述:構建就是以我們編寫的 Java 代碼、框架配置文件、國際化等其他資源文件、JSP 頁面和圖片等靜態資源作為“原材料”,去“生產”出一個可以運行的項目的過程。
那麼項目構建的全過程中都包含哪些環節呢?
構建的幾個過程
- 清理:刪除以前的編譯結果,為重新編譯做好準備。
- 編譯:將 Java 源程序編譯為字節碼文件。
- 測試:針對項目中的關鍵點進行測試,確保項目在迭代開發過程中關鍵點的正確性。
- 報告:在每一次測試後以標準的格式記錄和展示測試結果。
- 打包:將一個包含諸多文件的工程封裝為一個壓縮文件用於安裝或部署。Java 工程對應 jar 包,Web工程對應 war 包。
- 安裝:在 Maven 環境下特指將打包的結果——jar 包或 war 包安裝到本地倉庫中。
- 部署:將打包的結果部署到遠程倉庫或將 war 包部署到服務器上運行。
什麼是自動化構建
其實上述環節我們在 Eclipse 中都可以找到對應的操作,只是不太標準。那麼既然 IDE 已經可以進行構建了我們為什麼還要使用 Maven 這樣的構建工具呢?我們來看一個小故事:
- 這是陽光明媚的一天。托馬斯嚮往常一樣早早的來到了公司,衝好一杯咖啡,進入了自己的郵箱——很不幸,QA 小組發來了一封郵件,報告了他昨天提交的模塊的測試結果——有 BUG。“好吧,反正也不是第一次”,托馬斯搖搖頭,進入 IDE,運行自己的程序,編譯、打包、部署到服務器上,然後按照郵件中的操作路徑進行測試。“嗯,沒錯,這個地方確實有問題”,托馬斯說道。於是托馬斯開始嘗試修復這個 BUG,當他差不多有眉目的時候已經到了午飯時間。
- 下午繼續工作。BUG 很快被修正了,接著托馬斯對模塊重新進行了編譯、打包、部署,測試之後確認沒有問題了,回覆了 QA 小組的郵件。
- 一天就這樣過去了,明媚的陽光化作了美麗的晚霞,托馬斯卻覺得生活並不像晚霞那樣美好啊。
讓我們來梳理一下托馬斯這一天中的工作內容
從中我們發現,托馬斯的很大一部分時間花在了“編譯、打包、部署、測試”這些程式化的工作上面,而真正需要由“人”的智慧實現的分析問題和編碼卻只佔了很少一部分。
能否將這些程式化的工作交給機器自動完成呢?——當然可以!這就是自動化構建。
此時 Maven 的意義就體現出來了,它可以自動的從構建過程的起點一直執行到終點:
為什麼要選擇Maven
真的需要嗎?
傳統的Web開發即使不使用 Maven 我們仍然可以進行 B/S 結構項目的開發。從表述層、業務邏輯層到持久化層再到數據庫都有成熟的解決方案。
Maven 並不是直接用來輔助編碼的,它戰鬥的崗位並不是以上各層。所以我們有必要通過企業開發中的實際需求來看一看哪些方面是我們現有技術的不足。
為什麼需要?
添加第三方 jar 包
在今天的 JavaEE 開發領域,有大量的第三方框架和工具可以供我們使用。要使用這些 jar 包最簡單的方法就是複製粘貼到 WEB-INF/lib 目錄下。但是這會導致每次創建一個新的工程就需要將 jar 包重複複製到 lib 目錄下,從而造成工作區中存在大量重複的文件,讓我們的工程顯得很臃腫。
而使用 Maven 後每個 jar 包本身只在本地倉庫中保存一份,需要 jar 包的工程只需要以座標的方式簡單的引用一下就可以了。不僅極大的節約了存儲空間,讓項目更輕巧,更避免了重複文件太多而造成的混亂。
jar 包之間的依賴關係
jar 包往往不是孤立存在的,很多 jar 包都需要在其他 jar 包的支持下才能夠正常工作,我們稱之為
jar 包之間的依賴關係。最典型的例子是:commons-fileupload-1.3.jar 依賴於 commons-io-2.0.1.jar,如果沒有 IO 包,FileUpload 包就不能正常工作。
那麼問題來了,你知道你所使用的所有 jar 包的依賴關係嗎?當你拿到一個新的從未使用過的 jar 包,你如何得知他需要哪些 jar 包的支持呢?如果不瞭解這個情況,導入的 jar 包不夠,那麼現有的程序將不能正常工作。再進一步,當你的項目中需要用到上百個 jar 包時,你還會人為的,手工的逐一確認它們依賴的其他 jar 包嗎?這簡直是不可想象的。
而引入 Maven 後,Maven 就可以替我們自動的將當前 jar 包所依賴的其他所有 jar 包全部導入進來,無需人工參與,節約了我們大量的時間和精力。用實際例子來說明就是:通過 Maven 導入 commons-fileupload-1.3.jar 後,commons-io-2.0.1.jar 會被自動導入,程序員不必瞭解這個依賴關係。
下圖是 Spring 所需 jar 包的部分依賴關係
獲取第三方 jar 包
JavaEE 開發中需要使用到的 jar 包種類繁多,幾乎每個 jar 包在其本身的官網上的獲取方式都不盡相同。為了查找一個 jar 包找遍互聯網,身心俱疲,沒有經歷過的人或許體會不到這種折磨。不僅如此,費勁心血找的 jar 包裡有的時候並沒有你需要的那個類,又或者又同名的類沒有你要的方法——以不規範的方式獲取的 jar 包也往往是不規範的。
使用 Maven 我們可以享受到一個完全統一規範的 jar 包管理體系。你只需要在你的項目中以座標的方式依賴一個 jar 包,Maven 就會自動從中央倉庫進行下載,並同時下載這個 jar 包所依賴的其他 jar 包
——規範、完整、準確!一次性解決所有問題!
Tips:在這裡我們順便說一下,統一的規範幾乎可以說成是程序員的最高信仰。如果沒有統一的規範,就意味著每個具體的技術都各自為政,需要以諸多不同的特殊的方式加入到項目中;好不容易加入進來還會和其他技術格格不入,最終受苦的是我們。而任何一個領域的統一規範都能夠極大的降低程序
員的工作難度,減少工作量。例如:USB 接口可以外接各種設備,如果每個設備都有自己獨特的接口,那麼不僅製造商需要維護各個接口的設計方案,使用者也需要詳細瞭解每個設備對應的接口,無疑是非常繁瑣的。
將項目拆分成多個工程模塊
隨著 JavaEE 項目的規模越來越龐大,開發團隊的規模也與日俱增。一個項目上千人的團隊持續開發很多年對於 JavaEE 項目來說再正常不過。那麼我們想象一下:幾百上千的人開發的項目是同一個 Web 工程。那麼架構師、項目經理該如何劃分項目的模塊、如何分工呢?這麼大的項目已經不可能通過 package 結構來劃分模塊,必須將項目拆分成多個工程協同開發。
多個模塊工程中有的是 Java 工程,有的是 Web 工程。那麼工程拆分後又如何進行互相調用和訪問呢?這就需要用到 Maven 的依賴管理機制。大家請看我們的 Survey 調查項目拆分的情況:
上層模塊依賴下層,所以下層模塊中定義的 API 都可以為上層所調用和訪問。
怎樣使用Maven
Maven 的核心程序中僅僅定義了抽象的生命週期,而具體的操作則是由 Maven 的插件來完成的。可是 Maven 的插件並不包含在 Maven 的核心程序中,在首次使用時需要聯網下載。
下載得到的插件會被保存到本地倉庫中。本地倉庫默認的位置是:~.m2\\repository。(也可以自定義倉庫)
如果不能聯網可以使用我們提供的 RepMaven.zip 解壓得到。具體操作參見“Maven 操作指南.txt”。
Maven核心概念
本章節將詳細地梳理Maven的核心概念和功能點。
- Maven 核心概念
- Maven 能夠實現自動化構建是和它的內部原理分不開的,這裡我們從 Maven 的九個核心概念入手,看看 Maven 是如何實現自動化構建的。
- POM
- 約定的目錄結構
- 座標
- 依賴管理
- 倉庫管理
- 生命週期
- 插件和目標
- 繼承
- 聚合
概念
- Project Object Model:項目對象模型。將 Java 工程的相關信息封裝為對象作為便於操作和管理的模型。Maven 工程的核心配置。可以說學習 Maven 就是學習 pom.xml 文件中的配置。
POM.XML解讀
<project>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
<parent> /<parent>
<artifactid>
<groupid>
<version>
<relativepath>
<modelversion> 4.0.0 /<modelversion>
<groupid> asia.banseon /<groupid>
<artifactid> banseon-maven2 /<artifactid>
<packaging> jar /<packaging>
<version> 1.0-SNAPSHOT /<version>
<name> banseon-maven /<name>
<description> A maven project to study maven. /<description>
<prerequisites> /<prerequisites>
<maven>
<issuemanagement> /<issuemanagement>
<system> jira /<system>
<cimanagement> /<cimanagement>
<system>
<notifiers> /<notifiers>
<notifier> /<notifier>
<type>
<sendonerror>
<sendonfailure>
<sendonsuccess>
<sendonwarning>
<address> /<project>
<configuration>
<inceptionyear>
<mailinglists> /<mailinglists>
<mailinglist> /<mailinglist>
<name> Demo /<name>
<post> [email protected] /<post>
<subscribe> [email protected] /<subscribe>
<unsubscribe> [email protected] /<unsubscribe>
<archive> http:/hi.baidu.com/banseon/demo/dev/ /<archive>
<developers> /<developers>
<developer> /<developer>
<name> banseon /<name>
<email> [email protected] /<email>
<roles> /<roles>
<role> Project Manager /<role>
<role> Architect /<role>
<organization> demo /<organization>
<organizationurl> http://hi.baidu.com/banseon /<organizationurl>
<properties> /<properties>
<dept> No /<dept>
<timezone> -5 /<timezone>
<contributors> /<contributors>
<contributor> /<contributor>
<name><email>
<licenses> /<licenses>
<license> /<license>
<name> Apache 2 /<name>
<distribution> repo /<distribution>
<comments> A business-friendly OSS license /<comments>
<connection> /<connection>
scm:svn:http://svn.baidu.com/banseon/maven/banseon/banseon-maven2-trunk(dao-trunk)
<developerconnection> /<developerconnection>
scm:svn:http://svn.baidu.com/banseon/maven/banseon/dao-trunk
<organization> /<organization>
<name> demo /<name>
<build> /<build>
<sourcedirectory>
<scriptsourcedirectory>
<testsourcedirectory>
<outputdirectory>
<testoutputdirectory>
<extensions> /<extensions>
<extension> /<extension>
<groupid>
<artifactid>
<version>
<defaultgoal>
<resources> /<resources>
<resource> /<resource>
<targetpath>
<filtering>
<directory>
<includes>
<excludes>
<testresources> /<testresources>
<testresource> /<testresource>
<targetpath><filtering><directory><includes><excludes>
<directory>
<finalname>
<filters>
<pluginmanagement> /<pluginmanagement>
<plugins> /<plugins>
<plugin> /<plugin>
<groupid>
<artifactid>
<version>
<extensions>
<executions> /<executions>
<execution> /<execution>
<phase>
<goals>
<inherited>
<configuration>
<dependencies> /<dependencies>
<dependency> /<dependency>
<inherited>
<configuration>
<plugins> /<plugins>
<plugin> /<plugin>
<groupid><artifactid><version><extensions>
<executions> /<executions>
<execution> /<execution>
<dependencies> /<dependencies>
<dependency> /<dependency>
<goals><inherited><configuration>
<profiles> /<profiles>
<profile> /<profile>
<activation> /<activation>
<activebydefault>
<name> Windows XP /<name>
<family> Windows /<family>
<arch> x86 /<arch>
<version> 5.1.2600 /<version>
<property> /<property>
<name> mavenVersion /<name>
<value> 2.0.3 /<value>
<file> /<file>
<exists> /usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/ /<exists>
<missing> /usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/ /<missing>
<build> /<build>
<defaultgoal>
<resources> /<resources>
<resource> /<resource>
<targetpath><filtering><directory><includes><excludes>
<testresources> /<testresources>
<testresource> /<testresource>
<targetpath><filtering><directory><includes><excludes>
<directory><finalname><filters>
<pluginmanagement> /<pluginmanagement>
<plugins> /<plugins>
<plugin> /<plugin>
<groupid><artifactid><version><extensions>
<executions> /<executions>
<execution> /<execution>
<dependencies> /<dependencies>
<dependency> /<dependency>
<goals><inherited><configuration>
<plugins> /<plugins>
<plugin> /<plugin>
<groupid><artifactid><version><extensions>
<executions> /<executions>
<execution> /<execution>
<dependencies> /<dependencies>
<dependency> /<dependency>
<goals><inherited><configuration>
<modules>
<repositories> /<repositories>
<repository> /<repository>
<releases> /<releases>
<enabled><updatepolicy><checksumpolicy>
<snapshots> /<snapshots>
<enabled><updatepolicy><checksumpolicy>
<pluginrepositories> /<pluginrepositories>
<pluginrepository> /<pluginrepository>
<releases> /<releases>
<enabled><updatepolicy><checksumpolicy>
<snapshots> /<snapshots>
<enabled><updatepolicy><checksumpolicy>
<dependencies> /<dependencies>
<dependency> /<dependency>
<reports>
<reporting> /<reporting>
<dependencymanagement> /<dependencymanagement>
<dependencies> /<dependencies>
<dependency> /<dependency>
<distributionmanagement> /<distributionmanagement>
<properties>
<modules>
<repositories> /<repositories>
<repository> /<repository>
<releases> /<releases>
<enabled>
<updatepolicy>
<checksumpolicy>
<snapshots> /<snapshots>
<enabled><updatepolicy><checksumpolicy>
<name> banseon-repository-proxy /<name>
<layout> default /<layout>
<pluginrepositories> /<pluginrepositories>
<pluginrepository> /<pluginrepository>
<dependencies> /<dependencies>
<dependency> /<dependency>
<groupid> org.apache.maven /<groupid>
<artifactid> maven-artifact /<artifactid>
<version> 3.8.1 /<version>
<type> jar /<type>
<classifier>
<scope> test /<scope>
<systempath>
<exclusions> /<exclusions>
<exclusion> /<exclusion>
<artifactid> spring-core /<artifactid>
<groupid> org.springframework /<groupid>
<optional> true /<optional>
<reports>
<reporting> /<reporting>
<excludedefaults>
<outputdirectory>
<plugins> /<plugins>
<plugin> /<plugin>
<groupid>
<artifactid>
<version>
<inherited>
<configuration>
<reportsets> /<reportsets>
<reportset> /<reportset>
<configuration>
<inherited>
<reports>
<dependencymanagement> /<dependencymanagement>
<dependencies> /<dependencies>
<dependency> /<dependency>
<distributionmanagement> /<distributionmanagement>
<repository> /<repository>
<uniqueversion>
<name> banseon maven2 /<name>
<layout>
<snapshotrepository> /<snapshotrepository>
<uniqueversion>
<name> Banseon-maven2 Snapshot Repository /<name>
<layout>
<site> /<site>
<name> business api website /<name>
scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web
<downloadurl>
<relocation> /<relocation>
<groupid>
<artifactid>
<version>
<message>
<status>
<properties>
閱讀更多 java程序員工程師 的文章