Maven - dependency那些事兒

身邊有幾位剛使用Maven的同窗表示——在一個叫"pom.xml"的文件裏聲明一個依賴就不用去手動添加jar了,感受這東西和本身手動管理依賴沒太大區別。
固然,並非這樣,在此記錄dependency那些事兒。html

dependency

一個依賴能夠按照maven的座標標準進行定義。
好比:java

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>


上面是最多見的座標屬性,偶爾也會看到有classifier
下面簡單說明一下標籤:git

  • groupId:一般用做項目標識,好比SpringFramework項目的groupId是org.springframework。
    也可能會用做項目隸屬的組織的名稱,但組織下有多個項目則很差分辨,儘可能保證層次級別明確。
  • artifactId:級別低於groupId的項目標識,一般用於標識一個module,好比spring-aop。
  • classifier:用於標識隸屬於module的附件。
  • version:當前項目版本,版本的寫法應有相應的規範。
  • type:依賴的類型,一般不須要聲明,默認爲jar。
  • scope:依賴範圍,默認爲compile。
  • packaging:打包方式,默認爲jar。
  • optional:依賴是否可選。
  • exclusions:排除傳遞性依賴。

 

scope

引入Junit依賴時一般須要聲明test scope:github

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>

大概能猜出是測試時使用該依賴,但不徹底正確。
Maven編譯代碼時須要使用classpath,但classpath不止一種,而是:web

  • 編譯classpath
  • 測試classpath
  • 運行classpath


Maven會根據須要使用不一樣的classpath,而scope能夠用來控制依賴與這三種classpath之間的關係。 spring

  • compile:默認使用該項,對三種classpath都有效。
  • test:僅對測試classpath有效,如上面的Junit。
  • provided:對編譯和測試classpath有效,好比開頭貼出的servlet-api的依賴,會在運行時由app server提供,Maven不能夠重複引入。
  • runtime:對測試和運行classpath有效,編譯時無效。
  • system:對編譯和測試classpath有效,但必須經過systemPath顯示指定依賴文件的位置,可使用系統環境變量。
  • import:不針對任何一種classpath,該項用於導入其餘pom中的dependencyManagement元素。


一般會使用前三種。
scope不只用來控制依賴與classpath之間的關係,還會對依賴的傳遞性產生影響。
傳遞性依賴? 好比A依賴B,B依賴C,則A對於B是直接依賴,對於C是傳遞性依賴。
A對B、B對C的依賴範圍決定了A對C的依賴範圍。
如何決定? 下面給出一個關係表,垂直表示第一依賴,水平表示第二依賴,交叉單元格爲傳遞性依賴。apache

  compile test provided runtime
compile compile     runtime
test test     test
provided provided   provided provided
runtime runtime     runtime


考慮一下這樣的依賴關係,A-> C -> D(1.0)和A-> B -> D(2.0)
此時應該如何處理? 引入兩種D依賴是不可能的。
Maven有依賴調節原則:api

  • 路徑最近優先。
  • 當路徑長度相同,聲明順序優先。

對於上面的例子,A-> C -> D(1.0)和A-> B -> D(2.0)的路徑長度相同,但前者聲明早於後者,所以加入的傳遞性依賴則是D(1.0)。安全

另外,還須要考慮這樣一個場景。
A依賴B、B依賴X和Y,X和Y都是可選依賴,即<optional>true</optional>,且4個都是compile。
此時,X和Y則不會被傳遞,對A是不可見的。mvc

 

exclusions

但依賴調節並不解決全部問題,咱們還須要exclusions來進行排除依賴
例如這樣一個狀況,工程中引入了A,A依賴B,可是B的版本過舊。
此時可使用exclusions排除該傳遞性依賴,並顯示聲明一個最新版本的B依賴。
好比這樣:

<dependency>
    <groupId>com.lowagie</groupId>
    <artifactId>itext</artifactId>
    <version>4.2.1</version>
    <exclusions>
        <exclusion>
            <artifactId>bcmail-jdk14</artifactId>
            <groupId>bouncycastle</groupId>
        </exclusion>
        <exclusion>
            <artifactId>bcprov-jdk14</artifactId>
            <groupId>bouncycastle</groupId>
        </exclusion>
        <exclusion>
            <artifactId>bctsp-jdk14</artifactId>
            <groupId>bouncycastle</groupId>
        </exclusion>
    </exclusions>
</dependency>

 

properties

用於統一管理屬性,好比咱們引入不少spring framework:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.0.3 RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.0.3 RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jms</artifactId>
    <version>4.0.3 RELEASE</version>
</dependency>

可見版本都是同樣的,想更改版本時再一個一個修改太麻煩。


properties能夠解決這一問題:

<properties>    
    <spring.version>4.0.3.RELEASE</spring.version>
</properties>


引入spring能夠改成:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jms</artifactId>
    <version>${spring.version}</version>
</dependency>

這樣確實簡介了很多,但你可能仍然討厭XML。

興許,之後咱們不會再用XML寫構建文件。
咱們可能會用一些插件(好比Polyglot for Maven)或者其餘的什麼東西(好比Gradle)。

 

repository

能夠把Maven的倉庫分爲兩種:

  • 本地倉庫
  • 遠程倉庫

Maven尋找一個dependency時會先從本地倉庫查找,若是找不到則在遠程倉庫查找,發現則下載到本地倉庫使用。
若是都查找失敗,會提示build failure。

或者,咱們也能夠把本地的jar放到本地倉庫中:

mvn install:install-file -Dfile=jar包的路徑 -DgroupId=個人groupId -DartifactId=個人artifactId -Dversion=個人version -Dpackaging=jar


本地倉庫默認路徑是用戶目錄下的.m2/repository/
該路徑能夠在settings.xml中修改,好比:

<localRepository>
    /usr/local/maven/repository
</localRepository>


那麼遠程倉庫又在哪裏?
打開$M2_HOME/lib/maven-model-builder-3.2.1.jar裏的 org/apache/maven/model/pom-4.0.0.xml

看到遠程倉庫的設置以下:

<repositories>
    <repository>
        <id>central</id>
        <name>Central Repository</name>
        <url>http://repo.maven.apache.org/maven2</url>
        <layout>default</layout>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
 </repositories>


固然,咱們也能夠配置其餘遠程倉庫,好比這樣:

<repositories>
    <repository>
        <id>opensesame</id>
        <name>Alibaba OpenSource Repsoitory</name>
        <url>http://code.alibabatech.com/mvn/releases/</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

配置遠程倉庫時也須要注意一些選項

  • id:倉庫的惟一標識符
  • name:倉庫名稱
  • url:倉庫地址,一般都是http協議
  • layout:默認爲default,表示倉庫佈局爲maven2和maven3的佈局
  • release/snapshots
    • enabled:是否支持發佈版/快照版
    • updatePolicy:更新策略
      • 默認爲daily
      • always : 每次構建時檢查
      • never : 從不檢查
      • interval : X:每隔X分鐘間差
    • checksumPolicy:校驗策略,默認爲warn,另外有failignore


爲何區分release和snapshot? 不能只經過版本號進行區分嗎?

試想一下這樣的場景,假設有A和B兩個模塊,A依賴B,且B還沒有開發完成。
如何讓B模塊每次更新後讓A的開發人員獲取?
每次更新後提示A的開發人員從VCS上pull下來構建?
或者不停地換版本號? 確實,就算B有了變化,但version也是依賴的標識之一。

若是依賴是snapshot則能解決這樣的問題,snapshot發佈時會加上一個時間戳,每次構建A的時候會檢查B是否最新,間差更新策略就是上面的updatePolicy
另外,也能夠執行mvn clean install-U強制更新。


遠程倉庫不都是想訪問就訪問的,有些倉庫出於安全考慮,須要提供認證信息才能夠訪問。
認證必須在settings.xml中設置,下面是一個例子:

<servers>
   <server>
        <id>server001</id>
        <username>my_login</username>
        <password>my_password</password>
        <privateKey>${user.home}/.ssh/id_dsa</privateKey>
        <passphrase>some_passphrase</passphrase>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
        <configuration></configuration>
    </server>
</servers>
相關文章
相關標籤/搜索