在Mac OS X + Idea下搭建Maven項目 -- Maven的依賴管理

上一篇博文講到如何安裝maven,這篇算是它的續篇,總結下maven是如何管理依賴的。

maven強大之處就是管理依賴。通過依賴傳遞,依賴繼承,以及pom導入,可以輕鬆實現依賴的版本管理。通過依賴scope實現在不同的生命週期時段,加入依賴。

如下是一個最簡單的爲當前項目添加依賴的示例:
IntelliJ Idea > Preferences… > Build, Execution, Deployment > Build Tools > Maven
Importing一欄,將”Import Maven projects automatically” 勾選上。如果這一欄沒有勾選的話,Idea會在右上角有個漂浮提示,也可以從這個提示那裏點擊開啓。
接下來,往pom.xml裏添加一條依賴,IDE會自動將此依賴添加到External Libraries裏面。

     <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>

#### 依賴傳遞 ####
比如我在pom.xml里加上了junit. 而junit要依賴於hamcrest-core。但是我不用再添加對於hamcrest-core的依賴,maven會自動做掉,於是我的External Libraries裏面不僅有junit,還有hamcrest-core.

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

#### 依賴scope ####

  1. compile: 默認的scope,如果在dependency節點裏沒有寫scope,那麼它默認是compile
  2. provided: JDK/容器在運行時會產生/提供這個依賴
  3. runtime: 依賴僅在運行時需要,在編譯時是不需要的
  4. test: 依賴僅用於測試,並不用於真正的appliation,比如添加junit依賴時,就可以爲它加上scope = test,前提是application本身真的不需要用到junit
  5. system: 貌似已經棄用了…
  6. import: 導入別的pom的dependencyManagement部分

#### 依賴繼承 ####
依賴繼承有兩個重要作用:

  1. 將子項目的公用依賴加入到父項目裏,化簡子項目的pom.xml
  2. 通過父項目的dependencyManagement裏申明的版本號來管理所用依賴的版本

如下例子來自maven官方文檔。Project A是父項目。Project B是A的子項目,所以B繼承了A申明在dependencyManagement段落裏的依賴,即:a-1.2,b-1.0,c-1.0,d-1.2。

但是由於B自己本身有定義對於a和c的依賴,所以對於依賴a, B會用自己本身定義的a-1.0。對於依賴c,B裏面並未定義版本,所以maven會上溯至父親A中找到對c的版本定義,所以是c-1.0。對於依賴b,它沒有定義在B自己的pom裏,所以繼承自父親A,b-1.0。對於依賴d,父親A裏有,自己的dependencyManagement也有,優先選用自己的,所以是c-1.0。

  <parent>
    <artifactId>A</artifactId>
    <groupId>maven</groupId>
    <version>1.0</version>
  </parent>

Project A的pom.xml:

<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>A</artifactId>
 <packaging>pom</packaging>
 <name>A</name>
 <version>1.0</version>
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.2</version>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>b</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>c</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>d</artifactId>
       <version>1.2</version>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>

Project B的pom.xml:

<project>
  <parent>
    <artifactId>A</artifactId>
    <groupId>maven</groupId>
    <version>1.0</version>
  </parent>
  <modelVersion>4.0.0</modelVersion>
  <groupId>maven</groupId>
  <artifactId>B</artifactId>
  <packaging>pom</packaging>
  <name>B</name>
  <version>1.0</version>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>test</groupId>
        <artifactId>d</artifactId>
        <version>1.0</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>test</groupId>
      <artifactId>a</artifactId>
      <version>1.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>test</groupId>
      <artifactId>c</artifactId>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>

一般來說,將dependencyManagement置於頂層項目的pom.xml文檔中,用於依賴包的版本控制,以確保各個子項目中用到的依賴都是相同的版本。dependencyManagement僅申明依賴和版本,並不實際下載依賴包。

當子項目中的dependencies裏有申明某依賴且沒有版本號時,maven會上溯,直到在上層pom裏找到該依賴的版本。子項目不用顯示地寫依賴的版本,以達到統一管理依賴版本的目的。

如果想要將依賴傳遞下去(傳給子項目,或者傳給那些import 這個pom的項目),則把依賴定義在dependencyManagement部分。如果不想用父親/import進來的pom裏定義的依賴版本,則在dependency部分申明特定版本號的依賴。否則,就應該在dependency部分僅申明依賴,不申明依賴版本,統一用父親/import進來的pom裏定義的依賴版本,來實現版本管理。

#### 依賴導入 ####
在大型項目中,依賴導入使用的更多。這裏用依賴導入來實現剛剛在依賴繼承小節實現的B繼承A的目的。
在B的pom.xml的dependencyManagement部分,import A的pom:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>maven</groupId>
  <artifactId>B</artifactId>
  <packaging>pom</packaging>
  <name>B</name>
  <version>1.0</version>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>A</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>test</groupId>
        <artifactId>d</artifactId>
        <version>1.0</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>test</groupId>
      <artifactId>a</artifactId>
      <version>1.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>test</groupId>
      <artifactId>c</artifactId>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>

在大型項目中,某些模塊依賴某些項目是非常常見的,爲了使這些模塊的依賴項目版本統一,使用依賴繼承+依賴導入是一種非常好的實踐。在根pom中指明依賴版本,在模塊中導入根pom,統一使用根pom定義的版本。將來依賴版本有更新時,只用更改根pom裏的版本號即可。這一點頗有設計模式的味道…

首先在根pom–bom(bill of material)的dependencyManagement部分申明依賴project1和project2,版本的話則引用properties部分定義的變量。並且根pom裏指明子項目parent。

<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.test</groupId>
  <artifactId>bom</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>
  <properties>
    <project1Version>1.0.0</project1Version>
    <project2Version>1.0.0</project2Version>
  </properties>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.test</groupId>
        <artifactId>project1</artifactId>
        <version>${project1Version}</version>
      </dependency>
      <dependency>
        <groupId>com.test</groupId>
        <artifactId>project2</artifactId>
        <version>${project1Version}</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <modules>
    <module>parent</module>
  </modules>
</project>

接下來在parent項目的pom-dependencyManagement部分,定義了一些外部依賴,並指定了版本。而且還定義了子項目project1和project2.

<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>com.test</groupId>
    <version>1.0.0</version>
    <artifactId>bom</artifactId>
  </parent>

  <groupId>com.test</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
      </dependency>
      <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.1</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <modules>
    <module>project1</module>
    <module>project2</module>
  </modules>
</project>

接下來是project1和project2的pom,它們的pom裏只申明瞭dependency而並未申明版本,因爲要統一用父親parent pom裏定義的依賴版本。

<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>com.test</groupId>
    <version>1.0.0</version>
    <artifactId>parent</artifactId>
  </parent>
  <groupId>com.test</groupId>
  <artifactId>project1</artifactId>
  <version>${project1Version}</version>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
    </dependency>
  </dependencies>
</project>
<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>com.test</groupId>
    <version>1.0.0</version>
    <artifactId>parent</artifactId>
  </parent>
  <groupId>com.test</groupId>
  <artifactId>project2</artifactId>
  <version>${project2Version}</version>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
    </dependency>
  </dependencies>
</project>

最後,當別的項目要引用project1和project2時,直接在dependencyManagement部分導入根pom(即bom),然後在dependencies部分申明要用到的依賴。不用指明版本,因爲maven會取根pom(即bom)裏在properties部分定義的版本。

<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.test</groupId>
  <artifactId>use</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.test</groupId>
        <artifactId>bom</artifactId>
        <version>1.0.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.test</groupId>
      <artifactId>project1</artifactId>
    </dependency>
    <dependency>
      <groupId>com.test</groupId>
      <artifactId>project2</artifactId>
    </dependency>
  </dependencies>
</project>

maven官方文檔鏈接:
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章