1. 程式人生 > 其它 >大話 Maven 系列筆記(二)——Maven依賴(重點)

大話 Maven 系列筆記(二)——Maven依賴(重點)

第二章、Maven依賴(重點)

maven管理依賴也就是jar包牛逼之處是不用我們自己下載,會從一些地方自動下載

maven遠端倉庫: https://mvnrepository.com/

maven遠端倉庫: https://maven.aliyun.com/mvn/search

maven工程中我們依靠在pom.xml檔案進行配置完成jar包管理工作(依賴)

在工程中引入某個jar包,只需要在 pom.xml 中引入jar包的座標,比如引入log4j的依賴:

<dependencies> 
    <dependency> 
        <groupId>
junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> </dependencies>

Maven 通過 groupId 、 artifactId 與 version 三個向量來定位Maven倉庫其jar包所在的位置,並把對應的jar包引入到工程中來。

jar包會自動下載,流程如下

1、依賴的範圍

classpath就是編譯好的 class位元組碼檔案所在的路徑,類載入器( classloader )就是去對應的classpath 中加在class二進位制檔案。

普通java專案

META-INF中有個檔案,有以下內容,告訴jvm執行的時候去哪個類裡找main方法。

普通的java工程類路徑就是最外層的目錄。

1 Manifest-Version: 1.0

2 Main-Class: com.xinzhi.HelloUser

web專案

src 目錄下的配置檔案會和class檔案一樣,自動copy到應用的 WEB-INF/classes 目錄下 ,所以普通jar包 的類路徑就是根路徑,沒有資源,如果有配置檔案也放在src 目錄下,他會同步打包在類路徑下。 所以web專案的classpath是 WEB-INF/classes

maven專案

maven工程會將 src/main/java 和 src/main/resources 目錄下的檔案全部打包在classpath 中。執行時他們兩個的資料夾下的檔案會被放在一個資料夾下。

maven 專案不同的階段引入到classpath中的依賴是不同的,例如:

①編譯時 ,maven 會將與編譯相關的依賴引入classpath中

②測試時 ,maven會將測試相關的的依賴引入到classpath中

③執行時 ,maven會將與執行相關的依賴引入classpath中

而依賴範圍就是用來控制依賴於這三種classpath的關係。

依賴範圍:使用scope標籤表示依賴的範圍。

依賴範圍表示: 這個依賴(jar和裡面類)在專案構建的哪個階段起作用。

依賴範圍scope :

compile:預設, 參與構建專案的所有階段

test:測試,在測試階段使用, 比如執行mvn test會使用junit 。

provided: 提供者。 專案在部署到伺服器時,不需要提供這個依賴的jar , 而是由伺服器提供這個依賴的jar包,典型的是servlet 和jsp 依賴

1.1、編譯依賴範圍(compile)

該範圍就是預設依賴範圍,此依賴範圍對於編譯、測試、執行三種classpath都有效,舉個簡單的例子,假如專案中有 fastjson 的依賴,那麼 fastjson不管是在編譯,測試,還是執行都會被用到,因此 fastjson必須是編譯範圍(構件預設的是編譯範圍,所以依賴範圍是編譯範圍的無須顯示指定)

<dependency> 
    <groupId>com.alibaba</groupId> 
    <artifactId>fastjson</artifactId> 
    <version>1.2.68</version> 
</dependency> 

1.2、測試依賴範圍(test)

使用此依賴範圍的依賴,只對測試classpath有效,在編譯主程式碼和專案執行時,都將無法使用該依賴, 最典型的例子就是 Junit, 構件在測試時才需要,所以它的依賴範圍是測試,因此它的依賴範圍需要顯示指定為<scope>test</scope>,當然不顯示指定依賴範圍也不會報錯,但是該依賴會被加入到編譯和執行classpath中,造成不必要的浪費 。

<dependency> 
    <groupId>junit</groupId> 
    <artifactId>junit</artifactId> 
    <version>4.7</version> 
    <!-- 需要顯示的指定出來範圍,用<scope>標籤 -->
    <scope>test</scope> 
</dependency> 
1.3、已提供依賴範圍(provided)

使用該依賴範圍的maven依賴,只對編譯和測試的classpath有效,對執行的classpath無效,典型的例子就是servlet-api , 編譯和測試該專案的時候需要該依賴,但是在執行時,web容器已經提供的該依賴,所以執行時就不再需要此依賴,如果不顯示指定該依賴範圍,並且容器依賴的版本和maven依賴的版本不一致的話,可能會引起版本衝突,造成不良影響。

<dependency> 
    <groupId>javax.servlet</groupId> 
    <artifactId>javax.servlet-api</artifactId> 
    <version>4.0.1</version> 
    <scope>provided</scope> 
</dependency>
1.4、執行時依賴範圍(runtime)

使用該依賴範圍的maven依賴,只對測試和執行的classpath有效,對編譯的classpath無效,典型例子就是JDBC 的驅動實現,專案主程式碼編譯的時候只需要JDK 提供的JDBC 介面,只有在測試和執行的時候才需要實現上述介面的具體JDBC 驅動。

<dependency> 
    <groupId>mysql</groupId> 
    <artifactId>mysql-connector-java</artifactId> 
    <version>5.1.25</version> 
    <scope>runtime</scope> 
</dependency>

2、依賴的傳遞

jar其實也是別人寫的工程,他也會依賴其他的jar包,傳遞性讓我們可以不關心所依賴的jar他依賴了其他哪些jar ,只要我們添加了依賴,他會自動將他所依賴的jar統統依賴進來。

我們只需依賴A.jar ,其他的會自動傳遞進來。

依賴傳遞的原則:

最短路徑優先原則:如果A依賴於B,B依賴於C ,在B和C 中同時有log4j的依賴,並且這兩個版本不一致,那麼A會根據最短路徑原則,在A中會傳遞過來B的log4j版本。

路徑相同先宣告原則:如果工程同時依賴於B和A ,B和C沒有依賴關係,並且都有D的依賴,且版本不一致,那麼會引入在pom.xml中先宣告依賴的log4j版本

<dependency> 
<groupId>com.xinzi</groupId> 
<artifactId>B</artifactId> 
<version>1.5.3</version> 
</dependency> 
<dependency> 
<groupId>com.xinzhi</groupId> 
<artifactId>A</artifactId> 
<version>1.12.2</version> 
</dependency>

因為B優先宣告,所以會使用B中引入的D.jar。

不同範圍的依賴的傳遞性

A依賴B,B依賴C,A能否使用C呢?要看B依賴C的範圍是不是compile ,只有compile範圍的依賴是可以傳遞的

3、依賴的排除

不同版本的jar選一個會導致一個問題,1.3.2版本高,A.jar可能用到了高版本的一些新的方法,此時因為某些原因系統選擇了低版本,就會導致A.jar報錯,無法執行。那麼就要想辦法把低版本排除掉,一般高版本會相容低版本

結合上個例子,我們想把低版本的D.jar排除了,就可以這樣做,這樣系統就只能依賴高版本

<dependencies> 
    <dependency> 
        <groupId>com.xinzi</groupId> 
        <artifactId>B</artifactId> 
        <version>1.5.3</version> 
        
        <!-- 使用exclusion標籤,來定義需要排除的依賴 -->
        <exclusions> 
            <exclusion> 
                <artifactId>com.xinzhi</artifactId> 
                <groupId>D</groupId> 
            </exlcusion> 
        </exclusions> 
    </dependency>  
    
    <dependency> 
        <groupId>com.xinzhi</groupId> 
        <artifactId>A</artifactId> 
        <version>1.12.2</version> 
    </dependency>  
</dependencies> 

4、聚合和繼承

4.1、繼承

應用場景:

此時有兩個maven專案 : Maven_Parent使用4.0版本的junit,Maven_Son使用3.8版本的junit, 由於junit是test範圍的開發包,所以無法依賴不會被傳遞,那麼就會分散在各個專案模組中,這就可能導致版本不統一的問題.

解決的思路:

將junit依賴版本統一提到"父"版本中,在子工程中不指定版本,以父工程中統一設定版本為準,同時也便於修改.

4.1.1、建立一個Maven工程作為父工程,打包的方式為pom聚合模組(父模組)的打包方式必須為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>
  
  <!-- 父工程座標 -->
  <groupId>com.mt.sec</groupId>
  <artifactId>Maven_Parent</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <!-- 聚合工程打包方式為pom -->
  <packaging>pom</packaging>
  
  <dependencyManagement>
    <dependencies> 
        <!-- 單元測試 -->  
        <dependency>  
            <groupId>junit</groupId>  
            <artifactId>junit</artifactId>  
            <version>4.10</version>  
            <scope>test</scope>  
        </dependency>  
    </dependencies>
  </dependencyManagement>
  
  <!-- 定義聚合-->
  <modules>
    <!--  描述模組專案的 相對位置-->
    <module>../Maven_son</module>
  </modules>
  
</project>

4.1.2、建立一個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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
    <modelVersion>4.0.0</modelVersion><groupId>com.mt.sec</groupId>
    <artifactId>Maven_Son</artifactId>
    <version>0.0.1-SNAPSHOT</version>
   
    <dependencies>
        <!-- 單元測試 -->  
        <dependency>  
            <groupId>junit</groupId>  
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>  
        </dependency>  
    </dependencies>
  
</project>

4.1.3、在子工程中新增對父工程的引用

<parent>
    <groupId>com.mt.sec</groupId>
    <artifactId>Maven_Parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <!--  以當前專案為準的 父專案所在的相對路徑-->
    <relativePath>../Maven_Parent/pom.xml</relativePath>
</parent>

4.1.4、將子工程的座標與父工程座標中重複的內容刪除。此時子專案和父專案的groupId和version座標是一樣的,所以可以刪除掉重複的座標

<!-- 父工程座標 -->
<groupId>com.mt.sec</groupId>
<artifactId>Maven_Parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging><!-- 子工程座標 -->
<groupId>com.mt.sec</groupId>   <!--    與父工程相同刪除    -->
<artifactId>Maven_Son</artifactId>
<version>0.0.1-SNAPSHOT</version>   <!--    與父工程相同刪除    -->

4.1.5、在父工程中統一宣告junit的依賴。在子工程中刪除junit的版本

<!-- 父工程 -->
<dependencyManagement>
    <dependencies> 
        <dependency>  
            <groupId>junit</groupId>  
            <artifactId>junit</artifactId>  
            <version>4.10</version>  
            <scope>test</scope>  
        </dependency>  
    </dependencies>
</dependencyManagement><!-- 子工程 -->
<dependencies>
    <dependency>  
        <groupId>junit</groupId>  
        <artifactId>junit</artifactId>
        <version>4.10</version>     <!--    由父工程控制版本,子工程刪除  -->
        <scope>test</scope>  
    </dependency>  
</dependencies>

此時只需要修改父專案的 junit 版本,其他子專案junit依賴版本也會跟著修改

經過以上步驟,最終子工程的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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
    <parent>
        <groupId>com.mt.sec</groupId>
        <artifactId>Maven_Parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <!--  以當前專案為準的 父專案所在的相對路徑-->
        <relativePath>../Maven_Parent/pom.xml</relativePath>
    </parent>
 
    <modelVersion>4.0.0</modelVersion><artifactId>Maven_Son</artifactId>>
   
    <dependencies>
        <!-- 單元測試 -->  
        <dependency>  
            <groupId>junit</groupId>  
            <artifactId>junit</artifactId>
            <scope>test</scope>  
        </dependency>  
    </dependencies>
  
</project>
4.2、聚合

配置繼承之後執行安裝命令時要先安裝父工程,否則會出現安裝錯誤,那麼如果每個都需要一個一個的安裝,會非常的麻煩。聚合的作用就是一鍵安裝各個模組工程,一般情況下會在父工程中定義聚合,聚合模組(父模組)的打包方式必須為pom,否則無法完成構建

在 Parent專案中定義聚合

<!-- 定義聚合-->
<modules>
    <!--  描述模組專案的相對位置-->
    <module>../Maven_son</module>
</modules>

在定義聚合工程中進行maven安裝命令

此時maven會根據專案的繼承關係,依次安裝模組專案

可以被繼承的POM元素如下:

groupId :專案組ID,專案座標的核心元素

version :專案版本,專案座標的核心因素

properties :自定義的Maven屬性; 一般用於統一制定各個依賴的版本號

dependencies :專案的依賴配置; 公共的依賴

dependencyManagement :專案的依賴管理配置

repositories :專案的倉庫配置

build :包括專案的原始碼目錄配置、輸出目錄配置、外掛配置、外掛管理配置等

一些對專案的描述 :

description:專案的描述資訊

organization:專案的組織資訊

inceptionYear:專案的創始年份

url:專案的URL地址

developers:專案的開發者資訊

contributors:專案的貢獻者資訊

distributionManagement:專案的部署配置

issueManagement:專案的缺陷跟蹤系統資訊

ciManagement:專案的持續整合系統資訊

scm:專案的版本控制系統

malilingLists:專案的郵件列表資訊

reporting:包括專案的報告輸出目錄配置、報告外掛配置等