火箭發動機異常,SpaceX首次商業載人飛行發射推遲
1.引入好的maven文章:
來源 1:https://www.jianshu.com/p/0fb5e3fb704d【maven內部原理解析1】
來源 2:https://blog.csdn.net/lcgoing/article/details/91350857【maven內部原理解析2】 原作者:zlwen
maven內部執行原理解析1
maven至今還是Java程式語言構建的事實標準,大部分專案還在使用maven來進行構建,因此瞭解maven內部執行的原理對定位和分析問題還是很有裨益的。本篇文章主要介紹一些maven內部執行過程中的一些基本概念,相信看完後,對那麼些剛剛接觸maven的讀者來說maven將不再陌生。
在具體分析專案構建的過程前,需要了解maven的一些基本概念,這些概念十分重要,請務必理解清楚後再看下文。基本概念主要有:POM,Lifecycle。這兩個概念又會包含一些小的概念,下文會逐步講解。
POM: 注意這裡的POM不是maven中構建過程使用的配置檔案pom.xml,但他們之間還是有聯絡的。POM的全稱是Project Object Model,用通俗點的話說就是對要構建的專案進行建模,將要構建的專案看成是一個物件(Object),後文就使用PO來指代這個物件。既然是一個物件,那麼PO有哪些屬性呢?在maven中一個專案都是用一個唯一的座標(coordinate)來表示,座標由groupId, artifactId, version, classifier, type這五部分組成。這樣來說PO應該也要具備座標屬性。另外一方面,一個專案肯定不是孤立存在的,可能依賴於其他的一些專案,那麼也就是說PO應該具備dependencies這個屬性,用來表示其所依賴的外部專案。我們可以嘗試一下用Java程式碼來描述下PO這個物件:
class PO{ private String groupId; private String artifactId; private String version; private String classifier; private String type; private Set<PO> dependencies; }
我們知道XML的表達能力是很強大的,一個Java中的物件是可以用XML來描述,例如一個上面定義的PO物件則可以用下面的XML來描述(表達有不規範之處,理解其中的含義即可):
<PO> <groupId></groupId> <artifactId></artifactId> <version></version> <classifier><classifier> <type></type> <dependencies> <PO></PO> <PO></PO> ... </dependencies> </PO>
是不是好像和什麼有點類似?對,就是pom.xml。pom.xml就是PO物件的XML描述。上面的PO定義還不完整,我們繼續看下PO還有什麼其他的屬性。我們知道在Java中類是可以繼承的,一個物件在建立的時候會同時建立其父類物件,類似的,PO物件也有其父物件,用parent屬性來表示,並且PO物件會繼承其父物件的所有屬性。另外一方面,一個專案可能根據不同職責分為多個模組(module),所有模組其實也就是一個單獨的專案,只不過這些專案會使用其父物件的一些屬性來進行構建。我們將這些新的屬性加到PO的定義中去:
lass PO{ private String groupId; private String artifactId; private String version; private String classifier; private String type; private Set<PO> dependencies; private PO parent; private Set<PO> modules; }
再將這個定義用XML語言表示一下:
<PO> <parent></parent> <groupId></groupId> <artifactId></artifactId> <version></version> <classifier><classifier> <type></type> <dependencies> <PO></PO> <PO></PO> ... </dependencies> <modules> ... </modules> </PO>
是不是越來越像pom.xml了?對,這就是pom.xml的由來。再說一遍:pom.xml就是PO物件的XML描述。到此為止,相信你再看pom.xml檔案時,會有一個全新的認識。
上面說的這些PO屬性是專案的一些固有屬性,到目前為止,我們還沒有涉及專案的構建過程。構建過程對應的是PO物件的build屬性,那麼你應該馬上想到,在pom.xml中就是<build>元素中的內容。這裡就有引入maven中第二個核心概念:Lifecycle。Lifecycle直譯過來就是生命週期。我們平常會接觸到哪些週期呢?一年中春夏秋冬就是一個週期。一個週期中可能分為多個階段,比如這裡的春夏秋冬。在maven中一個構建過程就對應一個Lifecycle,這個Lifecycle也分為多個階段,每個階段叫做phase。你可能會問,那這個Lifecycle中包含多少個phase呢?一個標準的構建Lifecycle包含了如下的phase:
validate: 用於驗證專案的有效性和其專案所需要的內容是否具備 initialize:初始化操作,比如建立一些構建所需要的目錄等。 generate-sources:用於生成一些原始碼,這些原始碼在compile phase中需要使用到 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:打包 pre-integration-test:整合測試前置操作 integration-test:整合測試 post-integration-test:整合測試後置操作 install:將打包產物安裝到本地maven倉庫 deploy:將打包產物安裝到遠端倉庫
在maven中,你執行任何一個phase時,maven會將其之前的phase都執行。例如 mvn install,那麼maven會將deploy之外的所有phase按照他們出現的順序一次執行。
Lifecycle還牽涉到另外一個非常重要的概念:goal。注意上面Lifecycle的定義,也就是說maven為程式的構建定義了一套規範流程:第一步需要validate,第二步需要initialize... ... compile,test,package,... ... install,deploy,但是並沒有定義每一個phase具體應該如何操作。這裡的phase的作用有點類似於Java語言中的介面,只協商了一個契約,但並沒有定義具體的動作。比如說compile這個phase定義了在構建流程中需要經過編譯這個階段,但沒有定義應該怎麼編譯(編譯的輸入是什麼?用什麼編譯javac/gcc?)。這裡具體的動作就是由goal來定義,一個goal在maven中就是一個Mojo(Maven old java object)。Mojo抽象類中定義了一個execute()方法,一個goal的具體動作就是在execute()方法中實現。實現的Mojo類應該放在哪裡呢?答案是maven plugin裡,所謂的plugin其實也就是一個maven專案,只不過這個專案會引用maven的一些API,plugin專案也具備maven座標。
在執行具體的構建時,我們需要為lifecycle的每個phase都繫結一個goal,這樣才能夠在每個步驟執行一些具體的動作。比如在lifecycle中有個compile phase規定了構建的流程需要經過編譯這個步驟,而maven-compile-plugin這個plugin有個compile goal就是用javac來將原始檔編譯為class檔案的,我們需要做的就是將compile這個phase和maven-compile-plugin中的compile這個goal進行繫結,這樣就可以實現Java原始碼的編譯了。有點繞,多看幾遍。那麼有人就會問,在哪裡繫結呢?答案是在pom.xml<build>元素中配置即可。例如:
<build> <plugins> <plugin> <artifactId>maven-myquery-plugin</artifactId> <version>1.0</version> <executions> <execution> <id>execution1</id> <phase>test</phase> <configuration> <url>http://www.foo.com/query</url> <timeout>10</timeout> <options> <option>one</option> <option>two</option> <option>three</option> </options> </configuration> <goals> <goal>query</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
就將maven-myquery-plugin中的query這個goal繫結到了test這個phase,後續在maven執行到test phase時就會執行query goal。還有有人可能會問,我都沒有指定Java原始檔的位置,編譯啥?這就引出了maven的design principle。在maven中,有一個非常著名的principle就是convention over configuration(約定優於配置)。這一點和ant有非常大的區別,例如使用ant來進行編譯時,我們需要指定原始檔的位置,輸出檔案的位置,javac的位置,classpath... ...在maven中這些都是不需要,若沒有手動配置,maven預設從<專案根目錄>/src/main/java這個目錄去查詢Java原始檔,編譯後的class檔案會儲存在<專案根目錄>/target/classes目錄。在maven中,所有的PO都有一個根物件,就是Super POM。Super POM中定義了所有的預設的配置項。Super POM對應的pom.xml檔案可以在maven安裝目錄下lib/maven-model-builder-3.0.3.jar:org/apache/maven/model/pom-4.0.0.xml中找到。用一張圖來表示maven Lifecycle,phase,goal之間的關係:
maven內部執行原理解析2
在第一篇裡主要介紹了maven的幾個核心概念,這一篇裡我們就以一個簡單的例子來分析整個maven執行的過程。構建所使用的專案結構如下:
專案結構 主要是一個echo專案,其包含了兩個module,分別是api和biz。echo專案的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>org.maven</groupId> <artifactId>echo</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <modules> <module>api</module> <module>biz</module> </modules> </project>
這裡有個比較費解的地方就是<packaging>pom</packaging>。若<packaging>元素的內容是jar,那麼我們很好理解,也就是說這個專案最終會被打包成一個jar包。那<packaging>元素為pom又是什麼意思呢?從字面上的意思來看,這個專案將打包成一個pom。我們不妨去maven倉庫裡去瞧瞧(前提是已經在專案下運行了mvn install命令)。我們發現在<maven倉庫路徑>/org/maven/echo/1.0.0目錄下有一個echo-1.0.0.pom檔案,細心的讀者可能已經發現這個檔案其實和echo專案中的pom.xml是同一個檔案。這樣做的目的是什麼呢?還記得第一篇中說過的PO物件吧,我們說過PO物件也是有繼承關係的,比如說這裡echo專案對應的PO物件就是api專案對應的PO物件的父物件(api專案是echo專案的一個module,在api專案的pom.xml中<parent>元素的內容所對應的就是echo專案),而echo專案PO物件的父物件又是哪個呢?答案是Super POM對應的PO物件。這就是maven中project inheritance的概念。當實際執行maven命令的時候,會根據project inheritance關係對專案的pom.xml進行轉化,得到真正執行時所用到的pom.xml,即所謂的effective pom。而<packaging>pom</packaging>的作用就在這裡。因此可以得到一個結論:所有<packaging>元素為pom的專案其實並不會輸出一個可供外部使用,類似於jar包的東西。這類專案的作用有兩個:
-
管理子專案
例如這裡的api和biz就是echo專案的兩個module。若沒有echo這個父專案,我們需要到api和biz兩個專案下分別執行mvn install命令才能完成整個構建過程,而有了echo這個父專案之後,我們只需在echo專案中執行mvn install即可,maven會解析pom.xml,發現該專案有api和biz兩個module,它會分別到這兩個專案下去執行mvn install命令。當module數量比較多的時候,能大大提高構建的效率。 -
管理繼承屬性
比如api和biz都需要某個依賴,那麼在echo專案的pom.xml中宣告即可,因為根據PO物件的繼承關係,api和biz專案會繼承echo專案的依賴,這樣就可以減少一些重複的輸入。
effective pom包含了當前專案的PO物件,直到Super POM對應的PO物件中的資訊。要看一個專案的effective pom,只需在專案中執行
mvn help:effective-pom
命令即可檢視。這裡順帶說一句,有的同學可能不理解上面這個命令是什麼意思。maven命令的語法為
mvn [options] [goal(s)] [phase(s)]這裡出現了第一篇中講述的兩個概念:goal和phase。maven允許你執行一個或者多個goals/phases。很明顯這面的命令help:effective-pom並不是一個phase(maven構建過程中的phase請參考上一篇文章),那麼也就是說它是一個goal。對這個goal只不過是採用了縮寫的形式,其全稱是這樣的:
org.apache.maven.plugins:maven-help-plugin:2.2:effective-pom
以分號為分隔符,包含了groupId,artifactId,version,goal四部分。若groupId為org.apache.maven.plugins則可以使用上述的簡寫形式。也就是說
mvn help:effective-pom mvn org.apache.maven.plugins:maven-help-plugin:2.2:effective-pom
是等價的,都是執行了maven-help-plugin這個plugin中的effective-pom這個goal。
好了,繼續回到effective pom。我們說過maven在真正構建的時候用的就是effective pom,那麼說明effective pom中包含了構建的所有資訊,我們以biz專案中的effective pom為例來看下effective pom長什麼樣子。在biz專案中執行mvn help:effective-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> <parent> <groupId>org.maven</groupId> <artifactId>echo</artifactId> <version>1.0.0</version> </parent> <groupId>org.maven</groupId> <artifactId>echo-biz</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>org.maven</groupId> <artifactId>echo-api</artifactId> <version>1.0.0</version> <scope>compile</scope> </dependency> </dependencies> <build> <sourceDirectory>/Users/allstarw/workspace/own-proj/misc/maven/echo/biz/src/main/java</sourceDirectory> <scriptSourceDirectory>/Users/allstarw/workspace/own-proj/misc/maven/echo/biz/src/main/scripts</scriptSourceDirectory> <testSourceDirectory>/Users/allstarw/workspace/own-proj/misc/maven/echo/biz/src/test/java</testSourceDirectory> <outputDirectory>/Users/allstarw/workspace/own-proj/misc/maven/echo/biz/target/classes</outputDirectory> <testOutputDirectory>/Users/allstarw/workspace/own-proj/misc/maven/echo/biz/target/test-classes</testOutputDirectory> <resources> <resource> <directory>/Users/allstarw/workspace/own-proj/misc/maven/echo/biz/src/main/resources</directory> </resource> </resources> <testResources> <testResource> <directory>/Users/allstarw/workspace/own-proj/misc/maven/echo/biz/src/test/resources</directory> </testResource> </testResources> <directory>/Users/allstarw/workspace/own-proj/misc/maven/echo/biz/target</directory> <finalName>echo-biz-1.0.0</finalName> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>2.4.1</version> <executions> <execution> <id>default-clean</id> <phase>clean</phase> <goals> <goal>clean</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.3.1</version> <executions> <execution> <id>default-install</id> <phase>install</phase> <goals> <goal>install</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>2.5</version> <executions> <execution> <id>default-resources</id> <phase>process-resources</phase> <goals> <goal>resources</goal> </goals> </execution> <execution> <id>default-testResources</id> <phase>process-test-resources</phase> <goals> <goal>testResources</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.10</version> <executions> <execution> <id>default-test</id> <phase>test</phase> <goals> <goal>test</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <executions> <execution> <id>default-testCompile</id> <phase>test-compile</phase> <goals> <goal>testCompile</goal> </goals> </execution> <execution> <id>default-compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <version>2.3.2</version> <executions> <execution> <id>default-jar</id> <phase>package</phase> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.7</version> <executions> <execution> <id>default-deploy</id> <phase>deploy</phase> <goals> <goal>deploy</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>篇幅有點長,省略了部分內容。對比biz專案的pom.xml,我們發現effective pom中增加了Super POM中繼承過來的一些配置,比如說<sourceDirectory>定義了biz專案的原始碼路徑,以及Lifecycle中各個phase繫結的goal:
[phase] [goal] compile maven-compiler-plugin:2.3.2:compile package maven-jar-plugin:2.3.2:jar install maven-install-plugin:2.3.1:install ... ...
有了effective pom的概念之後,再來看maven構建的輸出日誌,是不是有點豁然開朗的感覺?
[INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Reactor Build Order: [INFO] [INFO] echo [INFO] echo-api [INFO] echo-biz [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building echo 1.0.0 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-install-plugin:2.3.1:install (default-install) @ echo --- [INFO] Installing /Users/allstarw/workspace/own-proj/misc/maven/echo/pom.xml to /Users/allstarw/.m2/repository/org/maven/echo/1.0.0/echo-1.0.0.pom [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building echo-api 1.0.0 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ echo-api --- [debug] execute contextualize [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /Users/allstarw/workspace/own-proj/misc/maven/echo/api/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ echo-api --- [WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent! [INFO] Compiling 1 source file to /Users/allstarw/workspace/own-proj/misc/maven/echo/api/target/classes [INFO] [INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ echo-api --- [debug] execute contextualize [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /Users/allstarw/workspace/own-proj/misc/maven/echo/api/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ echo-api --- [INFO] No sources to compile [INFO] [INFO] --- maven-surefire-plugin:2.10:test (default-test) @ echo-api --- [INFO] No tests to run. [INFO] Surefire report directory: /Users/allstarw/workspace/own-proj/misc/maven/echo/api/target/surefire-reports ------------------------------------------------------- T E S T S ------------------------------------------------------- Results : Tests run: 0, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] --- maven-jar-plugin:2.3.2:jar (default-jar) @ echo-api --- [INFO] Building jar: /Users/allstarw/workspace/own-proj/misc/maven/echo/api/target/echo-api-1.0.0.jar [INFO] [INFO] --- maven-install-plugin:2.3.1:install (default-install) @ echo-api --- [INFO] Installing /Users/allstarw/workspace/own-proj/misc/maven/echo/api/target/echo-api-1.0.0.jar to /Users/allstarw/.m2/repository/org/maven/echo-api/1.0.0/echo-api-1.0.0.jar [INFO] Installing /Users/allstarw/workspace/own-proj/misc/maven/echo/api/pom.xml to /Users/allstarw/.m2/repository/org/maven/echo-api/1.0.0/echo-api-1.0.0.pom [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building echo-biz 1.0.0 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ echo-biz --- [debug] execute contextualize [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /Users/allstarw/workspace/own-proj/misc/maven/echo/biz/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ echo-biz --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ echo-biz --- [debug] execute contextualize [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /Users/allstarw/workspace/own-proj/misc/maven/echo/biz/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ echo-biz --- [INFO] No sources to compile [INFO] [INFO] --- maven-surefire-plugin:2.10:test (default-test) @ echo-biz --- [INFO] No tests to run. [INFO] Surefire report directory: /Users/allstarw/workspace/own-proj/misc/maven/echo/biz/target/surefire-reports ------------------------------------------------------- T E S T S ------------------------------------------------------- Results : Tests run: 0, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] --- maven-jar-plugin:2.3.2:jar (default-jar) @ echo-biz --- [INFO] [INFO] --- maven-install-plugin:2.3.1:install (default-install) @ echo-biz --- [INFO] Installing /Users/allstarw/workspace/own-proj/misc/maven/echo/biz/target/echo-biz-1.0.0.jar to /Users/allstarw/.m2/repository/org/maven/echo-biz/1.0.0/echo-biz-1.0.0.jar [INFO] Installing /Users/allstarw/workspace/own-proj/misc/maven/echo/biz/pom.xml to /Users/allstarw/.m2/repository/org/maven/echo-biz/1.0.0/echo-biz-1.0.0.pom [INFO] ------------------------------------------------------------------------ [INFO] Reactor Summary: [INFO] [INFO] echo .............................................. SUCCESS [0.461s] [INFO] echo-api .......................................... SUCCESS [2.581s] [INFO] echo-biz .......................................... SUCCESS [0.382s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 3.593s [INFO] Finished at: Wed Jul 06 00:22:50 CST 2016 [INFO] Final Memory: 10M/156M [INFO] ------------------------------------------------------------------------日誌的輸出十分清楚,分別構建echo,api,biz這三個專案(因為biz專案依賴api專案,因此api專案需要首先構建)。對每個專案構建時,將lifecycle中的phase所對應的goal依次執行。