1. 程式人生 > >《Maven實戰》筆記

《Maven實戰》筆記

這就是 符號鏈接 doc comm 是什麽 打包 pom.xml projects href

maven是什麽

maven是

  • 構建工具
  • 依賴關系工具
  • 項目信息管理工具

而JAVA世界的ant只是一個構建工具,不具備依賴管理的功能,需要配合使用ivy進行依賴管理。

maven的安裝

下載maven,配置環境變量。
升級的技巧:使用符號鏈接,環境變量指向符號鏈接,升級的時候修改符號鏈接即可。

maven使用入門

手動搭建maven項目

  • 編寫pom
  • 編寫主代碼和測試代碼

使用ArcheType創建maven項目骨架

命令如下
mvn archetype:generate
實際上上述命令的完整格式是:
mvn groupId:artifactId:version:goal


即運行的是archetype插件的generate目標。
也可以為自己的項目開發archetype。

編譯,測試,打包,安裝,運行

  • 編譯: mvn clean compile
  • 測試:mvn clean test
  • 打包:mvn clean package
  • 安裝:mvn clean install
  • 運行
    • 使用maven-shade-plugin插件生成可執行的jar.
      • pom中配置shade插件。
      • 執行 mvn clean install,重新生成jar包。
    • 運行jar包。java -jar xxx.jar

坐標和依賴

maven坐標的各個元素

  • groupId
  • artifactId
  • version
  • packaging:打包方式。比如jar或者war。
  • classifier:附屬構件。比如javadoc和源代碼。

依賴的元素

  • groupId
  • artifactId
  • version
  • type:同坐標中的packaging。默認為jar。
  • scope:依賴範圍
  • optional
  • exclusions

依賴範圍

三種classpath:編譯classpath,測試classpath,運行classpath。

  • compile:對編譯、測試、運行三種classpath都有效。
  • test:只對測試classpath有效。比如JUnit。
  • provided:編譯和測試classpath有效,運行classpath無效。比如servlet API。
  • runtime:測試和運行classpath有效,編譯classpath無效。比如JDBC驅動實現。
  • system:與provided一致。只是這種情況必須顯示指定依賴文件的路徑,這樣就和本機系統綁定了,使得構建不具有移植性,慎用。
  • import:不會對三種classpath產生影響。

依賴範圍不僅可以控制依賴與三種classpath的關系,還對傳遞性依賴產生影響。

傳遞性依賴

傳遞性依賴機制:maven會解析各個直接依賴的pom,將那些必要的間接依賴以傳遞性依賴的形式引入到當前項目中。(我們只需要關心項目的直接依賴)

maven會自動解析所有項目的直接依賴和傳遞性依賴,確保每個構件只有唯一的版本在依賴中存在。最後解析後的這些依賴被稱為已解析依賴
相關命令
查看已解析依賴:mvn dependency:list
依賴樹:mvn dependency:tree
分析依賴:mvn dependency:analyze

生命周期和插件

生命周期和階段

maven對構建過程進行了抽象,被稱為生命周期。生命周期本身不做具體任務,實際的任務由插件完成。這是一種模板方法模式。

生命周期包含一些階段(phase),這些階段有前後依賴關系,後面的階段依賴前面的階段。可以定義多個生命周期,生命周期之間彼此是獨立的,不存在依賴關系。

Maven擁有三套獨立的生命周期,分別是clean、default和site。

  • clean生命周期的目的是清理項目。
  • default生命周期的目的是構建項目。
  • site生命周期的目的是建立項目站點。

clean生命周期

包含三個階段:

  • pre-clean
  • clean
  • post-clean

defalut生命周期

包含的階段太多,詳情 Introduction to the Build Lifecycle。

site生命周期

  • pre-site
  • site
  • post-site
  • site-deploy

命令行與生命周期的關系

常用的mvn clean compile命令實際上調用的是clean生命周期的clean階段和default生命周期的compile階段。

插件和插件目標

對於插件而言,為了能夠復用代碼,它能夠執行多個任務,實現多個功能,這些功能聚集在一個插件裏,每個功能就是一個插件目標。比如maven-dependency-plugin插件,它可以分析項目依賴,列出項目的依賴樹,找出無用依賴。

通常寫法是:插件:插件目標

插件綁定

將生命周期中的階段和插件目標綁定。
那麽在命令行輸入生命周期的階段,則對應的插件目標就會執行相應的任務。

Q:是否可以直接在命令行中直接指定執行某個插件目標‘???
A:可以。

多個插件目標可以綁定到同一個階段。

總結

A Build Lifecycle is Made Up of Phases
A Build Phase is Made Up of Plugin Goals

聚合和繼承

聚合

解決如下需求:想要用一條命令一次性構建多個項目(模塊)。
這就是maven聚合(多模塊)特性。
方法:增加一個聚合模塊,其中的pom.xml中的packaging為pom。

聚合模塊和其他模塊的目錄關系

不一定是父子關系,也可以是平行的目錄結構。

繼承

目的:解決多模塊maven項目的配置重復問題。
方法:增加一個父模塊,在父pom中聲明一些配置供子pom繼承。

父模塊和聚合模塊一般同時存在多模塊maven項目中。父模塊也要在聚合模塊中的modules標簽中配置。

可繼承的pom元素

  • groupId
  • version
  • dependencies
  • dependencyManagement
  • build
  • repositories
  • properties
  • ...

依賴管理

可以將一些依賴放到父模塊的dependencies元素中,這樣子類就無需配置了。但會存在一個問題:所有的子模塊都會依賴父模塊dependencies元素中聲明的依賴,即使一些子模塊並不需要這些依賴。

解決方法:
在父模塊中使用dependencyManagement元素聲明依賴,這些依賴不為直接被子模塊繼承。子模塊若要繼承父模塊dependencyManagement中聲明的某個依賴的話,則需要在子模塊中的dependencies元素中重新聲明(只需要配置groupId和artifactId即可)。
雖然這種方式不會大幅度的減少配置,但是由於在父模塊的pom中統一申明了依賴的版本,可以避免在子模塊中使用的依賴版本不一致的情況。

import依賴範圍

名為import的依賴範圍只在dependencyManagement元素下采用效果。其作用是將目標pom中的dependencyManagement配置導入並合並到當前pom中的dependencyManagement元素中。

插件管理

pluginManagement和dependencyManagement類似。

聚合與繼承的關系

目的不同:

  • 聚合是為了方便快速構建項目。
  • 繼承是為了消除重復配置。

聚合模塊 vs. 被聚合模塊:聚合模塊知道被聚合模塊,但被聚合模塊不知道聚合模塊的存在。
父模塊 vs. 子模塊:父模塊不知道那些子模塊繼承自它,但子模塊都知道自己的父模塊。

相同點:父模塊和聚合模塊都沒有實際內容,並且兩者的pom中的packaging都必須是pom。

實際項目中,會發現一個pom既是父pom,又是聚合pom,這麽做主要是為了方便。

約定優於配置

所有的pom都繼承自超級POM。
對於Maven3,超級POM在$MAVEN_HOME/lib/maven-model-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml路徑下。
對於Maven2,超級POM在$MAVEN_HOME/lib/maven-model-x.x.x-uber.jar中的org/apache/maven/pom-4.0.0.xml路徑下。
在超級POM中已經定義了源代碼的路徑、構建的輸出路徑等信息。

反應堆

構建一個多模塊項目時,由於模塊間存在繼承或者聚合關系,模塊間的構建是有先後關系的,整體構成一個有向無環圖DAG。反應堆就是所有模塊組成的一個構建結構。

持續集成

比如TensorFlow的持續集成:http://ci.tensorflow.org/

使用maven構建web應用

war文件的目錄結構

todo

web項目的maven目錄結構

todo

快速生成web項目的maven目錄結構

生成web項目的maven目錄結構

jetty-maven-plugin插件

doc

      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>8.1.13.v20130916</version>
        <configuration>
          <webApp>
            <contextPath>/</contextPath>
          </webApp>
          <connectors>
            <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
              <port>8081</port>
              <maxIdleTime>60000</maxIdleTime>
            </connector>
          </connectors>
        </configuration>
      </plugin>

http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin

使用cargo實現自動化部署

Cargo支持兩種本地部署的方式:standalone模式和existing模式。如下是standalone模式:

      <plugin>
        <groupId>org.codehaus.cargo</groupId>
        <artifactId>cargo-maven2-plugin</artifactId>
        <version>1.6.2</version>
        <configuration>
          <container>
            <containerId>tomcat8x</containerId>
            <home>D:\Program Files\apache-tomcat-8.0.23</home>
          </container>
          <configuration>
            <type>standalone</type>
            <home>${project.build.directory}/tomcat8x</home>
            <properties>
              <cargo.servlet.port>8181</cargo.servlet.port>
            </properties>
          </configuration>
        </configuration>
      </plugin>

existing模式:

      <plugin>
        <groupId>org.codehaus.cargo</groupId>
        <artifactId>cargo-maven2-plugin</artifactId>
        <version>1.6.2</version>
        <configuration>
          <container>
            <containerId>tomcat8x</containerId>
            <home>D:\Program Files\apache-tomcat-8.0.23</home>
          </container>
          <configuration>
            <type>existing</type>
            <home>D:\Program Files\apache-tomcat-8.0.23</home>
            <!-- existing模式下好像無法更改端口 -->
            <!--<properties>-->
              <!--<cargo.servlet.port>8080</cargo.servlet.port>-->
            <!--</properties>-->
          </configuration>
        </configuration>
      </plugin>

Archetype

Archetype Catalog

  • internal:maven-archetype-plugin內置的Archetype Catalog。
  • local:~/.m2/archetype-catalog.xml
  • remote:http://repo1.maven.org/maven2/archetype-catalog.xml https://repo.maven.apache.org/maven2/archetype-catalog.xml
  • file://...:本機任何位置上的archetype-catalog.xml文件。
  • http://...:使用http協議指定遠程的archetype-catalog.xml文件。

mvn archetype:generate卡住的問題

原因:
執行命令mvn archetype:generate時,maven-archetype-plugin插件會先尋找archetype-catalog.xml文件,默認是從中央庫中尋找該文件。由於中央庫訪問比較慢,所以出現卡頓現象。

解決方案:

  • 方案(1):加上archetypeCatalog參數
    mvn archetype:generate -DarchetypeCatalog=internal

  • 方案(2):配置一個國內的鏡像,加速對archetype-catalog.xml的訪問。比如阿裏雲的maven鏡像,如下:

      <mirror>
        <id>alimaven</id>
        <name>aliyun maven</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        <mirrorOf>central</mirrorOf>        
      </mirror>

經驗:安裝maven後一定要配置一個國內的中央庫鏡像,比如阿裏maven中央鏡像庫。因為後續很多mvn命令需要下載很多插件和依賴,網絡不好容易導致操作失敗。

阿裏雲maven庫列表

下載單個構建的源碼和文檔

mvn dependency:get -Dartifact=com.alibaba.citrus:citrus-webx-all:3.2.4:jar:sources
mvn dependency:get -Dartifact=com.alibaba.citrus:citrus-webx-all:3.2.4:jar:javadoc

《Maven實戰》筆記