Maven
一、Maven中的幾個概念
1. POM
我們在上篇文章中提到了maven的幾個核心概念,其中一個是POM。
POM就是Project Object Model項目對象模型。
將 Java 工程的相關信息封裝爲對象作爲便於操作和管理的模型。
pom.xml就是Maven 工程的核心配置。可以說學習 Maven 就是學習 pom.xml 文件中的配置。
我們會在後面不斷的學習,這裏就先不做展開。
2. 座標
說到座標,我們首先想到的應該是數學中的座標:
- 在一個平面中使用 x、y 兩個向量可以唯一的確定平面中的一個點。
- 在空間中使用 x、y、z 三個向量可以唯一的確定空間中的一個點。
而maven中的座標,
使用以下三個向量在Maven倉庫中唯一的確定一個Maven工程。
groupID
:公司或組織的域名倒序+當前項目的名稱artifactID
:當前項目的模塊名稱version
:當前模塊的版本
例如:
<groupId>com.atguigu.maven</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
這樣的定位方式我們又簡稱爲GAV,也就是上面三個單詞的首字母縮寫。
Maven工程的座標與倉庫中路徑的對應關係,
例如:
3. 倉庫
分類
倉庫分爲本地倉庫和遠程倉庫。
本地倉庫就是當前電腦上部署的倉庫目錄,爲當前電腦上所有的Maven工程服務。
遠程倉庫又分爲私服、中央倉庫、中央倉庫的鏡像。
- 私服:架設在當前局域網環境下,爲當前局域網範圍內的所有 Maven 工程服務。
- 中央倉庫:架設在 Internet 上,爲全世界所有 Maven 工程服務。
- 中央倉庫的鏡像:架設在各個大洲,爲中央倉庫分擔流量。減輕中央倉庫的壓力,同時更快的響應用戶請求。
倉庫中的內容
倉庫裏面保存的都是Maven工程。
倉庫中保存着:
- Maven自身所需要的插件
- 第三方框架或工具的jar包
- 我們自己開發的Maven工程
我們爲了介紹Maven的依賴,我們先要建立第二個Maven工程。
二、第2個Maven工程
搭建HelloFriend工程
①工程名:HelloFriend
②目錄結構與第一個Maven工程相同
③POM文件
<?xml version="1.0" ?>
<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.veeja.maven</groupId>
<artifactId>HelloFriend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HelloFriend</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.veeja.maven</groupId>
<artifactId>HelloMaven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
④主程序:
在src/main/java/com/veeja/maven目錄下新建文件HelloFriend.java
package com.veeja.maven;
import com.veeja.maven.HelloMaven;
public class HelloFriend {
public String sayHelloToFriend(String name){
HelloMaven helloMaven = new HelloMaven();
String str = helloMaven.sayHello(name)+" I am "+this.getMyName();
System.out.println(str);
return str;
}
public String getMyName(){
return "John";
}
}
⑤測試程序:
在/src/test/java/com/atguigu/maven目錄下新建測試文件HelloFriendTest.java
package com.veeja.maven;
import static junit.framework.Assert.assertEquals;
import org.junit.Test;
import com.veeja.maven.HelloMaven;
public class HelloFriendTest {
@Test
public void testHelloFriend(){
HelloFriend helloFriend = new HelloFriend();
String results = helloFriend.sayHelloToFriend("veeja");
assertEquals("Hello veeja! I am John",results);
}
}
我們的關注點在於,我們在這個HelloFriend工程裏面,用到了HelloMaven這個工程。這就產生了所謂的“依賴”。而我們爲什麼能使用呢,原因就在於我們在pom.xml中配置了這樣的依賴關係,也就是:
<dependency>
<groupId>com.veeja.maven</groupId>
<artifactId>HelloMaven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
那麼我們這樣配置到底能不能使用呢?我們接下來要試一試。
執行幾個命令
我們先來執行mvn compile
命令,看一下結果:
我們可以看到,構建失敗了,錯誤的信息爲:
[ERROR] Failed to execute goal on project HelloFriend: Could not resolve dependencies for project com.veeja.maven:HelloFriend:jar:0.0.1-SNAPSHOT: Could not find artifact com.veeja.maven:HelloMaven:jar:0.0.1-SNAPSHOT -> [Help 1]
它提示我們,找不到HelloMaven工件。
我們再來思考上面講的座標知識,
<dependency>
<groupId>com.veeja.maven</groupId>
<artifactId>HelloMaven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
這樣的一段依賴配置,已經確定了對應的目錄。而我們在倉庫中,並沒有找到相應的目錄及文件。
三、依賴
Maven解析依賴信息時會到本地倉庫中查找被依賴的jar包。
對於我們自己開發的Maven工程,使用install命令
安裝後就可以進入倉庫。
對於上面的例子中,我們應該先把HelloMaven添加進倉庫中,也就是在HelloMaven工程下執行mvn install
。
這時呢,我們在進入我們的本地倉庫中,就能找到對應的目錄和文件了。
這時我們再次編譯HelloFriend工程,
我們這次看到,編譯就成功了。
依賴的範圍
我們在配置文件中的<dependency>
標籤中,
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.veeja.maven</groupId>
<artifactId>HelloMaven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
發現有一個<scope>
的子標籤,這就是指的依賴的範圍。
依賴的範圍常用的三個取值爲compile
、test
、provided
三個。
① 從項目結構的角度理解compile和test的區別
結合具體例子:
對於HelloFriend來說,HelloMaven就是服務於主程序的,junit是服務於測試程序的。
HelloFriend主程序需要 HelloMaven是非常明顯的,測試程序由於要調用主程序所以也需要HelloMaven,所以compile範圍依賴對主程序和測試程序都應該有效。
HelloFriend的測試程序部分需要junit也是非常明顯的,而主程序是不需要的,所以test範圍依賴僅僅對於主程序有效。
② 從開發和運行這兩個不同階段理解 compile 和 provided 的區別
③ 有效性總結
[1]compile範圍依賴
- 對主程序是否有效:有效
- 對測試程序是否有效:有效
- 是否參與打包:參與
- 是否參與部署:參與
- 典型例子: spring-core
[2]test範圍依賴
- 對主程序是否有效:無效
- 對測試程序是否有效:有效
- 是否參與打包:不參與
- 是否參與部署:不參與
- 典型例子: junit
[3]provided範圍依賴
- 對主程序是否有效:有效
- 對測試程序是否有效:有效
- 是否參與打包:不參與
- 是否參與部署:不參與
- 典型例子: servlet-apijar
關於依賴的其他幾個特點,我們將在後面進行介紹。
四、Maven的生命週期
1. 什麼是生命週期?
各個構建環節的執行順序不能打亂,必須按照既定的正確的順序來執行。
Maven的核心程序中定義了抽象的生命週期,生命週期中各個階段的具體任務是由插件來完成的。
Maven 生命週期定義了各個構建環節的執行順序,有了這個清單,Maven 就可以自動化的執行構建命 令了。
Maven 有三套相互獨立的生命週期,分別是:
- Clean Lifecycle 在進行真正的構建之前進行一些清理工作。
- Default Lifecycle 構建的核心部分,編譯,測試,打包,安裝,部署等等。
- Site Lifecycle 生成項目報告,站點,發佈站點。
它們是相互獨立的,你可以僅僅調用 clean 來清理工作目錄,僅僅調用 site 來生成站點。當然你也可以 直接運行 mvn clean install site 運行所有這三套生命週期。
每套生命週期都由一組階段(Phase)組成,我們平時在命令行輸入的命令總會對應於一個特定的階段。比 如,運行 mvn clean,這個 clean 是 Clean 生命週期的一個階段。有 Clean 生命週期,也有 clean 階段。
2. Clean生命週期
Clean 生命週期一共包含了三個階段:
①pre-clean 執行一些需要在 clean 之前完成的工作
②clean 移除所有上一次構建生成的文件
③post-clean 執行一些需要在 clean 之後立刻完成的工作
3. Site生命週期
①pre-site 執行一些需要在生成站點文檔之前完成的工作
②site 生成項目的站點文檔
③post-site 執行一些需要在生成站點文檔之後完成的工作,並且爲部署做準備
④site-deploy 將生成的站點文檔部署到特定的服務器上
這裏經常用到的是 site 階段和 site-deploy 階段,用以生成和發佈 Maven 站點,這可是 Maven 相當強大 的功能,Manager 比較喜歡,文檔及統計數據自動生成,很好看。
4. Default生命週期
Default 生命週期是 Maven 生命週期中最重要的一個,絕大部分工作都發生在這個生命週期中。這裏, 只解釋一些比較重要和常用的階段:
validate
generate-sources
process-sources
generate-resources
process-resources
複製並處理資源文件,至目標目錄,準備打包。
compile
編譯項目的源代碼。
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources
複製並處理資源文件,至目標測試目錄。
test-compile
編譯測試源代碼。
process-test-classes test
使用合適的單元測試框架運行測試。這些測試代碼不會被打包或部署。
prepare-package package
接受編譯好的代碼,打包成可發佈的格式,如 JAR。
pre-integration-test
integration-test
post-integration-test
verify install
將包安裝至本地倉庫,以讓其它項目依賴。
deploy
將最終的包複製到遠程的倉庫,以讓其它開發人員與項目共享或部署到服務器上運行。
5. 生命週期與自動化構建
運行任何一個階段的時候,它前面的所有階段都會被運行,例如我們運行 mvn install 的時候,代碼會 被編譯,測試,打包。這就是 Maven 爲什麼能夠自動執行構建過程的各個環節的原因。此外,Maven 的插 件機制是完全依賴 Maven 的生命週期的,因此理解生命週期至關重要。
五、插件和目標
Maven 的核心僅僅定義了抽象的生命週期,具體的任務都是交由插件完成的。
每個插件都能實現多個功能,每個功能就是一個插件目標。
Maven 的生命週期與插件目標相互綁定,以完成某個具體的構建任務。
例如:compile
就是插件 maven-compiler-plugin 的一個目標;pre-clean
是插件 maven-clean-plugin 的一個目標。
END.