1. 程式人生 > 其它 >技能篇:maven的簡易教程

技能篇:maven的簡易教程


highlight: androidstudio
theme: cyanosis

前言

maven是最流行的專案構建系統,如果是java相關的開發,可以說是不可或缺的。雖然還有另外一個模組管理工具grade正在崛起, 不過多數公司常用的還是maven

  • Maven 和 Maven的倉庫
  • Maven 命令和構建生命週期
  • maven專案pom.xml格式檔案詳解
  • Maven怎麼做到傳遞依賴與排除依賴
  • Maven的聚合和繼承
  • mvn使用例項

關注公眾號,一起交流,微信搜一搜: 潛行前行

Maven 和 Maven的倉庫

Maven倉庫用來存放Maven所管理Jar包。分為兩種:本地倉庫 和 中央倉庫

  • 本地倉庫:Maven本地的Jar包倉庫
  • 中央倉庫:Maven官方提供的遠端倉庫,Maven 中央倉庫是由 Maven 社群提供的倉庫,其中包含了大量常用的庫。中央倉庫包含了絕大多數流行的開源Java構件
  • 遠端倉庫: Maven 在中央倉庫中也找不到依賴的檔案,它會停止構建過程並輸出錯誤資訊到控制檯。為避免這種情況,Maven 提供了遠端倉庫的概念,它是開發人員自己定製倉庫,包含了所需要的程式碼庫或者其他工程中用到的 jar 檔案

Maven 命令和構建生命週期

階段 處理 描述
validate 驗證專案 驗證專案是否正確且所有必須資訊是可用的
compile 執行編譯 原始碼編譯在此階段完成
test 測試 使用適當的單元測試框架(例如JUnit)執行測試。
package 打包 建立JAR/WAR包如在 pom.xml 中定義提及的包
verify 檢查 對整合測試的結果進行檢查,以保證質量達標
install 安裝 安裝打包的專案到本地倉庫,以供其他專案使用
deploy 部署 拷貝最終的工程包到遠端倉庫中,以共享給其他開發人員和工程
  • 當一個階段通過 Maven 命令呼叫時,如mvn compile ,該階段之前以及包括該階段在內的所有階段都會被執行
  • maven 還有一個clean命令,用於移除所有上一次構建生成的檔案
  • 在構建環境中,常使用mvn clean deploy
    命令來清除,及構建、部署專案到遠端倉庫中

maven專案 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.0http://maven.apache.org/maven-v4_0_0.xsd">     
    <!--父專案的座標-->    
    <parent>  
        <artifactId/> <!--被繼承的父專案的構件識別符號-->    
        <groupId/>  <!--被繼承的父專案的全球唯一識別符號-->      
        <version/>  <!--被繼承的父專案的版本-->    
        <!-- 父專案的pom.xml檔案的相對路徑-->    
        <relativePath/>    
    </parent>    
    <!--宣告專案描述符遵循哪一個POM模型版本。模型本身的版本很少改變-->       
    <modelVersion>4.0.0</modelVersion>     
    <!--專案的全球唯一識別符號,通常使用全限定的包名區分該專案和其他專案。並且構建時生成的路徑也是由此生成, 如com.ex.app生成的相對路徑為:/com/ex/app-->     
    <groupId>com.ex.app</groupId>     
    <!-- 構件的識別符號,它和group ID一起唯一標識一個構件-->     
    <artifactId>erhuowang-maven2</artifactId>     
    <!--專案產生的構件型別,例如jar、war、ear、pom。外掛可以建立他們自己的構件型別-->     
    <packaging>war</packaging>     
    <!--專案當前版本,格式為:主版本.次版本.增量版本-限定版本號-->     
    <version>1.0-SNAPSHOT</version>     
    <!--專案的名稱, Maven產生的文件用-->     
    <name>erhuo-maven</name>     
    <!--專案主頁的URL, Maven產生的文件用-->     
    <url>http://erhuowang.cn</url>     
    <!-- 專案的詳細描述-->     
    <description>A maven project to study maven.</description>     
    <!-- 描述了這個專案構建環境中的前提條件。 --> 
    <prerequisites> 
        <!-- 構建該專案或使用該外掛所需要的Maven的最低版本 --> 
        <maven></maven> 
    </prerequisites>
------------------------------------------------------------------------------------     
    <!--該元素描述了專案相關的所有依賴。 這些依賴組成了專案構建過程中的一個個環節。-->    
    <dependencies>     
      <dependency>    
        <!--依賴的group ID-->    
        <groupId>org.apache.maven</groupId>     
        <!--依賴的artifact ID-->    
        <artifactId>maven-artifact</artifactId>     
        <!--依賴的版本號。 在Maven 2裡, 也可以配置成版本號的範圍。-->    
        <version>3.8.1</version>     
        <!-- 依賴型別,預設型別是jar。它通常表示依賴的檔案的副檔名,但也有例外。一個型別可以被對映成另外一個副檔名或分類器。型別經常和使用的打包方式對應, 儘管這也有例外。一些型別的例子:jar,war,ejb-client和test-jar。如果設定extensions為 true,就可以在 plugin裡定義新的型別。所以前面的型別的例子不完整。-->    
        <type>jar</type>    
        <classifier></classifier>    
        <!--依賴範圍。在專案釋出過程中,幫助決定哪些構件被包括進來。欲知詳情請參考依賴機制。    
            - compile :預設範圍,用於編譯      
            - provided:類似於編譯,但支援你期待jdk或者容器提供,類似於classpath      
            - runtime: 在執行時需要使用      
            - test:    用於test任務時使用      
            - system: 需要外在提供相應的元素。通過systemPath來取得      
            - systemPath: 僅用於範圍為system。提供相應的路徑      
            - optional:   當專案自身被依賴時,標註依賴是否傳遞。用於連續依賴時使用-->     
        <scope>test</scope>       
        <!--當計算傳遞依賴時, 從依賴構件列表裡,列出被排除的依賴構件-->    
        <exclusions>    
         <exclusion>     
                <artifactId>spring-core</artifactId>     
                <groupId>org.springframework</groupId>     
            </exclusion>     
        </exclusions>       
        <!--可選依賴,如果你在專案B中把C依賴宣告為可選,你就需要在依賴於B的專案(例如專案A)中顯式的引用對C的依賴。可選依賴阻斷依賴的傳遞性。-->     
        <optional>true</optional>    
     </dependency>    
    </dependencies>  
----------------------------------------------------------------------------------------------
    <build>    
      <!--該元素設定了專案原始碼目錄,當構建專案的時候,構建系統會編譯目錄裡的原始碼。該路徑是相對於pom.xml的相對路徑。-->    
      <sourceDirectory/>    
      <scriptSourceDirectory/> <!--絕大多數情況下,該目錄下的內容 會被拷貝到輸出目錄(因為指令碼是被解釋的,而不是被編譯的)。-->      
      <testSourceDirectory/>   <!--該元素設定了專案單元測試使用的原始碼目錄。該路徑是相對於pom.xml的相對路徑。-->     
      <outputDirectory/>     <!--被編譯過的應用程式class檔案存放的目錄。--> 
      <testOutputDirectory/>  <!--被編譯過的測試class檔案存放的目錄。-->       
      <!--使用來自該專案的一系列構建擴充套件-->    
      <extensions>     
           <extension>   <!--描述使用到的構建擴充套件。-->      
            <groupId/>   <!--構建擴充套件的groupId-->   
            <artifactId/> <!--構建擴充套件的artifactId-->  
            <version/> <!--構建擴充套件的版本-->       
           </extension>    
      </extensions>    
      <!--當專案沒有規定目標(Maven2 叫做階段)時的預設值-->    
      <defaultGoal/>    
      <!--這個元素描述了專案相關的所有資源路徑列表,例如和專案相關的屬性檔案,這些資源被包含在最終的打包檔案裡。-->    
      <resources> <!--這個元素描述了專案相關或測試相關的所有資源路徑-->    
          <resource>  <!-- 描述了資源的目標路徑。該路徑相對target/classes目錄-->    
            <targetPath/>    
            <filtering/> 
            <directory/>   <!--描述存放資源的目錄,該路徑相對POM路徑-->   
            <includes/> <!--包含的模式列表,例如**/*.xml.-->    
            <excludes/> <!--排除的模式列表,例如**/*.xml-->     
            </resource>    
      </resources>    
      <!--這個元素描述了單元測試相關的所有資源路徑,例如和單元測試相關的屬性檔案。-->    
      <testResources>    
         <!--這個元素描述了測試相關的所有資源路徑-->    
         <testResource></testResource>    
      </testResources>    
      <targetPath/>
      <filtering/>
      <directory/> <!--構建產生的所有檔案存放的目錄-->    
          <includes/><excludes/>    
      <directory/> 
      <finalName/> <!--產生的構件的檔名,預設值是${artifactId}-${version}。-->    
      <!--當filtering開關開啟時,使用到的過濾器屬性檔案列表-->    
      <filters/>    
      
       <!--使用的外掛列表-->    
      <plugins>    
        <!--參見build/pluginManagement/plugins/plugin元素-->    
        <plugin> </plugin>    
      </plugins>  
      
      <!--子專案可以引用的預設外掛資訊。該外掛配置項直到被引用時才會被解析或繫結到生命週期。給定外掛的任何本地配置都會覆蓋這裡的配置-->    
      <pluginManagement>  
           <plugins>  
               <!--plugin元素包含描述外掛所需要的資訊。-->    
               <plugin>    
                  <groupId/>   <!--外掛在倉庫裡的group ID--> 
                  <artifactId/> <!--外掛在倉庫裡的artifact ID-->  
                  <version/>   
                  <extensions/>    
                  <executions> <!--在構建生命週期中執行一組目標的配置。每個目標可能有不同的配置。-->   
                    <execution> <!--execution元素包含了外掛執行需要的資訊--> 
                      <id/>  <!--執行目標的識別符號,用於標識構建過程中的目標,或者匹配繼承過程中需要合併的執行目標--> 
                      <phase/> <!--綁定了目標的構建生命週期階段,如果省略,目標會被繫結到源資料裡配置的預設階段-->      
                      <goals/>  <!--配置的執行目標-->    
                      <inherited/>    <!--配置是否被傳播到子POM-->    
                      <configuration/> <!--作為DOM物件的配置-->     
                    </execution>    
                  </executions>    
                  <!--專案引入外掛所需要的額外依賴-->    
                  <dependencies>    
                   <!--參見dependencies/dependency元素-->    
                   <dependency>    
                    ......    
                   </dependency>    
                  </dependencies>           
                  <!--作為DOM物件的配置-->    
                  <configuration/>    
               </plugin>    
           </plugins>    
      </pluginManagement>    
    </build>    
 -----------------------------------------------------------------------------------
    <!--在列的專案構建profile,如果被啟用,會修改構建處理-->    
    <profiles>    
      <!--根據環境引數或命令列引數啟用某個構建處理-->    
      <profile>    
       <id/>      
       <activation>    
        <!--profile預設是否啟用的標誌-->    
        <activeByDefault/> 
        <jdk/>jdk版本,如:1.8</jdk>    
        
        <!--當匹配的作業系統屬性被檢測到,profile被啟用。os元素可以定義一些作業系統相關的屬性。-->
        <!--如果Maven檢測到某一個屬性(其值可以在POM中通過${名稱}引用),其擁有對應的名稱
        值,Profile就會被啟用。如果值欄位是空的,那麼存在屬性名稱欄位就會啟用profile,
        否則按區分大小寫方式匹配屬性值欄位-->    
        <property> 
          <name>mavenVersion</name> <!--啟用profile的屬性的名稱-->       
          <!--啟用profile的屬性的值-->    
          <value>2.0.3</value>    
        </property>    
        <!--提供一個檔名,通過檢測該檔案的存在或不存在來啟用profile。missing檢查檔案是否存在,如果不存在則啟用 -->    
        <file>    
         <!--如果指定的檔案存在,則啟用profile。-->    
         <exists>/usr/local/workspace/</exists>    
         <!--如果指定的檔案不存在,則啟用profile。-->    
         <missing>/usr/local/workspace/</missing>    
        </file>    
       </activation>    
       <!--構建專案所需要的資訊。參見build元素-->    
       <build>    
            <defaultGoal/>    
            <resources>    
             <resource>    
              <targetPath/><filtering/><directory/><includes/><excludes/>    
             </resource>    
            </resources>    
            <testResources>    
             <testResource>    
              <targetPath/><filtering/><directory/><includes/><excludes/>    
             </testResource>    
            </testResources>    
            <directory/><finalName/><filters/>    
            <pluginManagement>    
             <plugins>    
              <!--參見build/pluginManagement/plugins/plugin元素-->    
              <plugin>    
               <groupId/><artifactId/><version/><extensions/>    
               <executions>    
                <execution>    
                 <id/><phase/><goals/><inherited/><configuration/>    
                </execution>    
               </executions>    
               <dependencies>    
                <!--參見dependencies/dependency元素-->    
                <dependency>    
                 ......    
                </dependency>    
               </dependencies>    
               <goals/><inherited/><configuration/>    
              </plugin>    
             </plugins>    
            </pluginManagement>    
            <plugins>    
             <!--參見build/pluginManagement/plugins/plugin元素-->    
             <plugin>    
              <groupId/><artifactId/><version/><extensions/>    
              <executions>    
               <execution>    
                <id/><phase/><goals/><inherited/><configuration/>    
               </execution>    
              </executions>    
              <dependencies>    
               <!--參見dependencies/dependency元素-->    
               <dependency>    
                ......    
               </dependency>    
              </dependencies>    
              <goals/><inherited/><configuration/>    
             </plugin>    
            </plugins>    
       </build>    
       <modules/>   
         <!--子專案相對路徑-->
         <module></module>
       </modules>          
       <!--發現依賴和擴充套件的遠端倉庫列表。-->    
       <repositories>    
           <!--參見repositories/repository元素-->    
           <repository>    
             <releases>    
              <enabled/><updatePolicy/><checksumPolicy/>    
             </releases>    
             <snapshots>    
              <enabled/><updatePolicy/><checksumPolicy/>    
             </snapshots>    
             <id/><name/><url/><layout/>    
           </repository>    
       </repositories>    
       <!--發現外掛的遠端倉庫列表,這些外掛用於構建和報表-->    
       <pluginRepositories>    
           <!--包含需要連線到遠端外掛倉庫的資訊.參見repositories/repository元素--> 
           <pluginRepository>    
             <releases>    
              <enabled/><updatePolicy/><checksumPolicy/>    
             </releases>    
             <snapshots>    
              <enabled/><updatePolicy/><checksumPolicy/>    
             </snapshots>    
             <id/><name/><url/><layout/>    
           </pluginRepository>    
       </pluginRepositories>    
       <!--該元素描述了專案相關的所有依賴 -->    
       <dependencies>    
         <!--參見dependencies/dependency元素-->    
         <dependency/>   
       </dependencies>    
       <dependencyManagement>  
           <dependencies>    
             <!--參見dependencies/dependency元素-->    
             <dependency>    
             ......    
             </dependency>    
           </dependencies>    
       </dependencyManagement>    
       <!--參見distributionManagement元素-->    
       <distributionManagement>    
        ......    
       </distributionManagement>    
       <!--參見properties元素-->    
       <properties/>    
      </profile>    
    </profiles>    
 ------------------------------------------------------------------------------------     
    <!-- 聚合模組被構建成專案的一部分。列出的每個模組元素是指向該模組的目錄的相對路徑 --> 
    <modules>
        <!--子專案相對路徑-->
        <module></module>
    </modules> 
 ------------------------------------------------------------------------------------ 
    <repositories>  <!--發現依賴和擴充套件的遠端倉庫列表。-->      
     <!--包含需要連線到遠端倉庫的資訊-->    
     <repository>    
         <releases> <!--如何處理遠端倉庫裡釋出版本的下載-->    
          <!--true或者false表示該倉庫是否為下載某種型別構件(釋出版,快照版)開啟。 -->    
         <enabled/>    
          <!-- 這裡的選項是:always(一直),daily(預設,每日),interval:X(這裡X是以分鐘為單位的時間間隔),或者never(從不)。-->    
          <updatePolicy/>    
          <!--當Maven驗證構件校驗檔案失敗時該怎麼做:ignore(忽略),fail(失敗),或者warn(警告)。-->   
          <checksumPolicy/>    
         </releases>    
         <!-- 如何處理遠端倉庫裡快照版本的下載。有了releases和snapshots這兩組配置,POM就可以在每個單獨的倉庫中,為每種型別的構件採取不同的 策略-->    
         <snapshots>    
          <enabled/><updatePolicy/><checksumPolicy/>    
         </snapshots>    
         <!--遠端倉庫唯一識別符號。可以用來匹配在settings.xml檔案裡配置的遠端倉庫-->    
         <id>banseon-repository-proxy</id>     
         <!--遠端倉庫名稱-->    
         <name>banseon-repository-proxy</name>     
         <!--遠端倉庫URL,按protocol://hostname/path形式-->    
         <url>http://192.168.1.169:9999/repository/</url>  
         <layout>default</layout>               
     </repository>     
    </repositories>    
------------------------------------------------------------------------------------
    <!--發現外掛的遠端倉庫列表,這些外掛用於構建和報表-->    
    <pluginRepositories>    
     <!--包含需要連線到遠端外掛倉庫的資訊.參見repositories/repository元素-->    
     <pluginRepository>    
      ......    
     </pluginRepository>    
    </pluginRepositories>        
------------------------------------------------------------------------------------
    <!-- 繼承自該專案的所有子專案的預設依賴資訊。這部分的依賴資訊不會被立即解析,而是當子專案宣告一個依賴(必須描述group ID和 artifact ID資訊),如果group ID和artifact ID以外的一些資訊沒有描述,則通過group ID和artifact ID 匹配到這裡的依賴,並使用這裡的依賴資訊。-->    
    <dependencyManagement>    
      <dependencies>    
       <!--參見dependencies/dependency元素-->    
       <dependency>    
        ......    
       </dependency>    
      </dependencies>    
    </dependencyManagement>       
---------------------------------------------------------------------------------------------  
    <!--專案分發資訊,在執行mvn deploy後表示要釋出的位置。有了這些資訊就可以把網站部署到遠端伺服器或者把構件部署到遠端倉庫。-->     
    <distributionManagement>    
        <!--部署專案產生的構件到遠端倉庫需要的資訊-->    
        <repository>    
         <!--是分配給快照一個唯一的版本號-->    
         <uniqueVersion/>    
         <id>banseon-maven2</id>     
         <name>banseon maven2</name>     
         <url>file://${basedir}/target/deploy</url>     
         <layout/>    
        </repository>   
        <!--部署專案的網站需要的資訊-->     
        <site>    
         <!--部署位置的唯一識別符號,用來匹配站點和settings.xml檔案裡的配置-->     
            <id>banseon-site</id>     
            <!--部署位置的名稱-->    
            <name>business api website</name>     
            <!--部署位置的URL,按protocol://hostname/path形式-->    
            <url>     
                scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web      
            </url>     
        </site>    
        <!-- 給出該構件在遠端倉庫的狀態。不得在本地專案中設定該元素,因為這是工具自動更新的。有效的值有:none(預設),converted(倉庫管理員從 Maven 1 POM轉換過來),partner(直接從夥伴Maven 2倉庫同步過來),deployed(從Maven 2例項部 署),verified(被核實時正確的和最終的)。-->    
       <status/>           
    </distributionManagement>  
---------------------------------------------------------------------------------------------- 
    <!--以值替代名稱,Properties可以在整個POM中使用,也可以作為觸發條件(見settings.xml配置檔案裡activation元素的說明)。格式是<name>value</name>。-->    
    <properties/>    
</project>    

Maven怎麼做到傳遞依賴與排除依賴

  • 傳遞依賴:如果我們的專案引用了一個Jar包,而該Jar包又引用了其他Jar包,那麼在預設情況下專案編譯時,Maven會把直接引用和簡潔引用的Jar包都下載到本地
  • 排除依賴:如果我們只想下載直接引用的Jar包,那麼需要在pom.xml中做如下配置
<exclusions>
    <exclusion>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
    </exclusion>
</exclusions>
  • 依賴衝突:若專案中多個Jar同時引用了相同的Jar時,會產生依賴衝突,但Maven採用了兩種避免衝突的策略,因此在Maven中是不存在依賴衝突的
    • 短路優先,例如A.jar —> B.jar —> X.jar;C.jar —> X.jar,優先使用短路徑的X.jar
    • 宣告優先;若引用路徑長度相同時,在pom.xml中誰先被宣告

Maven的聚合和繼承

  • 同時配置多個執行專案稱之聚合,聚合的專案有一個父類pom.xml檔案,而各個專案也有屬於自己的pom.xml
  • 在聚合多個專案時,如果這些被聚合的專案中需要引入相同的Jar,那麼可以將這些Jar寫入父pom.xml中,各個子專案繼承該pom即可
  • 父pom.xml
<!-- 聚合多個專案  -->
<modules>
    <module>../模組A</module>
    <module>../模組B</module>
    <module>../模組C</module>
</modules>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.2</version>
        </dependency> 
    </dependencies>
</dependencyManagement>
  • 子pom.xml配置
<!-- 繼承了 父類的 org.apache.shiro jar  -->
<parent>
    <groupId>父pom所在專案的groupId</groupId>
    <artifactId>父pom所在專案的artifactId</artifactId>
    <version>父pom所在專案的版本號</version>
</parent>

mvn使用例項

//建立Maven的普通java專案
mvn archetype:create -DgroupId=packageName -DartifactId=projectName
//編譯原始碼
mvn compile 
//只測試而不編譯,也不測試編譯
mvn test -skipping compile -skipping test-compile 
//執行測試
mvn test 
//清除產生的專案
mvn clean
//在本地Repository中安裝jar
mvn install
//清除舊的專案,並生成新的jar
mvn clean install
//清除舊的專案,並生成新的jar且上傳遠端倉庫
mvn clean install deploy

歡迎指正文中錯誤

參考文章