MAVEN 座標與依賴

1、前言

咱們知道,maven經過依賴的座標來查找依賴,並經過必定的規則來自動管理依賴。本篇文章將經過對座標和依賴的講解,來告訴咱們maven管理依賴的原理與過程,並介紹如何經過一些工具來實現依賴的優化。java

2、座標

咱們一般會經過下面的方式來引入一個依賴spring

<dependency>
    <groupId>xxx.xx.xx</groupId>
    <artifactId>xx</artifactId>
	<version>1.1</artifactId>
</dependency>
複製代碼

groupId,artifactId,version就是一個依賴的座標,但它只是maven查找依賴所須要必要座標,其實座標還包括classfier和extension。下面咱們來詳細介紹一下每個座標元素的含義:sql

  • groupId:即組Id,它表明一個組織結果,命名相似於域名或java中package 的命令方式
  • artifactId:它的定位是組織內一個項目的名稱,groupId+artifactId保證了項目的惟一性
  • version:version即一個項目的迭代版本,更加詳細版本介紹能夠參考:https://juejin.im/post/5a169ad551882512a860fb44
  • classfier:classfier並不常見,它表明了一個項目的構件。一般咱們只會將代碼打包成一個jar或war等,好比xx-xxx-1.1.jar,這只是項目默認的主構件;咱們還能夠同時打包xx-xxx-1.1-sources.jar, xx-xxx-1.1-javadoc.jar, sources 和 javadoc就是classfier,它表明項目的副構件。如何集成打包參考:http://maven.apache.org/plugins/maven-assembly-plugin/
  • extension/packaging:即擴展名,也就是咱們的打包方式。默認狀況下會打包成jar,也能夠打包成war和pom 等 上面五種元素肯定了依賴的惟一地址,除groupId外決定了包的名稱,(如何查找依賴將在接下文章中給出) 包名規則: artifactId-version-classfier.extension

3、依賴調解

maven依賴調解有兩條很是明確的規則: 路徑最短優先 優先定義優先 舉個例子以下:apache

root
+--a:1
   +--c:1
+--b:1
   +--c:2
      +--d:1
   +--a:2
複製代碼

pathLength(a:1)=1,pathLength(a:2)=2,所以a:2就會被自動exclude掉,maven不會將該版本的jar包下載至本地。 c:1和c:2的路徑長度均爲1,但因爲c:1定義在前,會被自動引入,c:2就會被exclude掉。 注:這裏你們可能會有一些疑問,c:2引入的d:1也會被exclude掉嗎?答案是確定的。這種簡單粗暴的的規則,極大簡化了maven管理依賴的成本。api

4、依賴範圍

maven有三類classpath(經過classpath查找加載相應資源),編譯期classpath,測試期classpath及運行期classpath。maven 在編譯,測試,運行期間所須要的資源是有所不一樣的,因此在管理maven 依賴時,也會按照對應的scope進行不一樣行爲的管理。bash

maven有如下幾種scope: compile:一般狀況下,咱們並不會手動設置scope的範圍,默認的就是compile,此scope下的依賴對三類classpath均有效。jvm

  • test:test 指僅對測試有效,對編譯和運行無效
  • provided: 指在運行時,該依賴沒必要顯示引入,已有容器或其它提供
  • runtime:指運行時引進,對編譯期和測試期有效
  • system:相似於provied,通常指在maven 倉庫中找不到,但能夠由jdk或者是jvm提供,這種類型的dependency引入時,須要指定路徑,以下所示:
<dependency>
      <groupId>sun.jdk</groupId>
      <artifactId>tools</artifactId>
      <version>1.5.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/../lib/tools.jar</systemPath>
    </dependency>
    <dependency>
      <groupId>javax.sql</groupId>
      <artifactId>jdbc-stdext</artifactId>
      <version>2.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/lib/rt.jar</systemPath>
    </dependency>
複製代碼
  • import:僅應用於dependencyManagement 中引入pom
classpath(編譯) classpath(測試) classpath(運行) 示例
compile Y Y Y spring-core
test Y JUnit
provided Y Y servlet-api
runtime Y Y JDBC
system Y Y

你們看到這裏可能會有疑惑,scope如何影響依賴傳遞。 一個簡單的計算方式:scope(上層依賴)&scope(間接依賴),即直接依賴和間接依賴的交集 好比A(runtime)→B(test) 則該B依賴只會對測試期有效maven

5、 dependencyManagement

dependencyManagement 是maven 2.0.6加入的標籤,它的出現的緣由在於推進pom文件的良好管理。主要做用能夠總結爲兩個方面:ide

  • 版本管理:指的是咱們能夠經過parent pom或者bom實現maven版本的統一管理,不管從公司角度,組織角度及項目的多模塊的角度,這都將是一個很好的管理方式。在maven官方文檔中有這麼一句話:

When referring to artifacts whose poms have transitive dependencies the project will need to specify versions of those artifacts as managed dependencies. Not doing so will result in a build failure since the artifact may not have a version specified. (This should be considered a best practice in any case as it keeps the versions of artifacts from changing from one build to the next)工具

maven 依賴的一個最佳實踐:全部的transive依賴都要顯示地聲明版本,防止不一樣編譯行爲形成的編譯結果不一樣

  • 依賴聚合:指咱們將公共依賴用bom進行管理,包括版本及exclusion,項目在引入依賴時,只須要引入頂層bom及聲明所須要加載的依賴便可。 這兩個方式不但方便了項目或公司對 依賴版本的統一管理,也有利於項目pom的精簡化。 說了 dependencyManagement的好處,這裏不得不強調一些使用dependencyManagement的一些注意事項(依賴引入規則),它和依賴引入規則和dependency有很大不一樣,我也將其總結成三個規則:
  • 優先定義規則
  • 顯示聲明優先
  • bom 優先與parent
<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>X</artifactId>
 <packaging>pom</packaging>
 <name>X</name>
 <version>1.0</version>
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.1</version>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>b</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>
複製代碼
<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>Y</artifactId>
 <packaging>pom</packaging>
 <name>Y</name>
 <version>1.0</version>
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.2</version>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>c</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>
複製代碼
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>maven</groupId>
  <artifactId>Z</artifactId>
  <packaging>pom</packaging>
  <name>Z</name>
  <version>1.0</version>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>X</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>Y</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>
複製代碼

Z同時引入了X與Y,X與Y同時都引入了依賴a,根據優先定義優先,則會引入X中a也就是1.1版本。 須要注意的是,即使X中再引入其它bom,也會優先使用X中的,而不會採用路徑長度最短優先的原則。 咱們看一下項目使用:

<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>test</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
  
   
    <dependencies>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>X</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>Y</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
 
      <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.3</version>
     </dependency>
    </dependencies>
</project>
複製代碼

若是在一個項目中顯示定義了a,根據顯示定義優先,此pom將不會引入X,Y中定義的a,所以,此時的版本應爲1.3 應該注意的是,不只僅會引入bom中版本,還會使用bom中的其它元素,好比exclusion,scope,type

相關文章
相關標籤/搜索