前情回顧
在上一節中介紹了通過工具eclipse構建了maven項目,並且僅僅做了簡單的運行演示,本節將通過eclipse構建出一個項目中的幾個模塊,並且通過這幾個模塊的聯繫講解maven中依賴的特性。
項目構建
本章通過一個典型的項目構建過程來學習Maven的依賴傳遞性。
項目獲取地址http://download.csdn.net/detail/songdeitao/6927445
總共分爲三個模塊的項目編寫user-core,user-log,user-service,在user-core中主要實現基本的實體類,初始文件,dao的編寫,在user-log中簡單模擬日誌文件的記錄,在user-service模塊中主要引入前兩個模塊,從而進行編寫service模塊的功能,在這裏模塊的編寫不是重點,這些都會給出代碼,然而進行Maven依賴與傳遞的講解纔是重點,所以很多時候代碼都是爲了演示出效果,和實際開發還是有些差別,但所指代的思想是項目中所存在的。
普通依賴
Maven的依賴是使用Maven座標來定位的,而Maven座標主要由GAV(groupId, artifactId, version)構成,因此,使用任何一個依賴之間,你都需要知道它的Maven座標,在之前的第二章節中,從引入了Maven的中央工廠的網頁,在此引入一個常用的Maven搜索jar包的資源庫網頁http://www.mvnrepository.com/,在此可以查找所需要的jar文件的GAV,比如在本文的第一章節的如下配置:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
可以通過如下列圖所示的步驟進行查找到,而且以後的jar包查找過程都是按照此步驟進行獲取,然後複製到pom.xml<dependencies>元素下,Maven就能在本地或者遠程倉庫中找到對應的jar包(不一定可以找到所有的jar文件)
圖1
圖2
圖3
此配置聲明瞭一個對junit的依賴,它的groupId是junit, artifactId是junit, version是4.10。這一組GAV構成了一個Maven座標,基於此,Maven就能在本地或者遠程倉庫中找到對應的junit-4.10.jar文件。傳遞依賴
一:
首先緊跟第二章節的新建項目構建出如下圖所示的結構圖,
圖4
通過此模塊的構建,主要說明Maven的一下幾個問題
1、目錄結構的默認構建,比如資源文件的src/main/resources目錄的構建
2、pom.xml文件的使用到的jar包的引入,比如在user-core中的文件內容如下所示:
<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.steven.user</groupId>
<artifactId>user-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>user-core</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.1.1.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.8</version>
</dependency>
</dependencies>
</project>
通過資源庫中查找到相應的jar包,放到pom.xml中之後,Eclipse就會自動會和本地資源庫或者遠程倉庫中進行匹配,如果本地中沒有,就會通過網絡下載從遠程倉庫中下載到本地倉庫中。
3、進行Maven項目模塊的打包和加入到本地資源庫的命令,如圖所示
圖5
這樣就可以執行打包或者將打包後的jar添加到本地倉庫中。
二:
接着引入user-log,user-service
圖6 圖7
其中user-log的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.steven.user</groupId>
<artifactId>user-log</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>user-log</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.4</version>
</dependency>
</dependencies>
</project>
其中user-service的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.steven.user</groupId>
<artifactId>user-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>user-service</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>user-log</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>user-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
此時細心的讀者會發現在user-service的pom文件中出現${project.groupId}和${project.version}的寫法,這是Maven的內置隱式變量,常用的如下介紹:
${basedir} 項目根目錄
${project.build.directory} 構建目錄,缺省爲target
${project.build.outputDirectory} 構建過程輸出目錄,缺省爲target/classes
${project.build.finalName} 產出物名稱,缺省爲${project.artifactId}-${project.version}
${project.packaging} 打包類型,缺省爲jar
${project.xxx} 當前pom文件的任意節點的內容(這裏所使用到的)
注意:
在完成user-service對user-log和user-service模塊的jar包引入的時候,一定要將這兩個模塊進行install處理,這樣在user-service中才可以訪問到前兩個模塊的jar包。
傳遞依賴
此時打開user-service的pom的dependency hierarchy圖,如圖所示:
圖8
會發現在user-log中使用log4j-1.2.4.jar而user-core中使用log4j-1.2.14.jar,但user-service包含user-log和user-core後,所使用的是log4j-1.2.4,爲什麼不使用新的版本呢?
這是因爲我在user-service中將user-log寫在了user-core前面。但難道誰寫在前面就在前面了嗎?
那我就將這兩個配置調換一下,得到的圖如圖9所示
圖9
再看log4j變成了log4j-1.2.14.jar(圖中沒有標出,但不難看出),那確實是這樣嗎?然後看圖8中dom4j是1.5版本,在圖9中調換過位置後還是1.5版本,怎麼回事?細心的讀者會發現log4j是出於user-core和user-log的同一級別,而dom4j在user-core和user-log卻不是在同一級別。
奧,我明白了,原來是這麼一回事:
結論:
1、當依賴的級別相同時,引入最先導入的jar包
2、當依賴級別不同時候,引入級別最近的jar包
那我偏要使用dom4j1.6.1的版本,那怎麼辦呢?
排除依賴
Maven很智能,在此提供一個元素,exclusion,只要在不想要的模塊中添加此元素,比如不想要user-log的dom4j1.5版本,則只要在user-service中這樣編寫即可:
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>user-log</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
</exclusion>
</exclusions>
</dependency>
此時在查看user-service的pom的dependency hierarchy圖,發現已經成功使用dom4j1.6.1版本了,如圖所示
圖10
依賴範圍(scope)
讀者還會發現,在圖8,9,10中,每個jar後都有類似[compile]的標識,這是什麼意思呢?這裏將引入Maven的依賴範圍概念。
什麼是依賴範圍呢?
引入:
Maven在編譯主代碼的時候需要使用一套classpath,在編譯和執行測試的時候會使用另一套classpath,實際運行項目的時候,又會使用一套classpath。
依賴範圍就是用來控制依賴與這三種classpath(編譯classpath、測試classpath、運行classpath)的關係,
Maven有以下幾種依賴範圍:
compile: 編譯依賴範圍。
如果沒有指定,就會默認使用該依賴範圍。使用此依賴範圍的Maven依賴,對於編譯、測試、運行三種classpath都有效。
test: 測試依賴範圍。
使用此依賴範圍的Maven依賴,只對於測試classpath有效,在編譯主代碼或者運行項目的使用時將無法使用此類依賴。典型的例子就是JUnit,它只有在編譯測試代碼及運行測試的時候才需要。這也是本文的pom文件中爲何junit的scope是使用test範圍的原因。
provided: 已提供依賴範圍。
使用此依賴範圍的Maven依賴,對於編譯和測試classpath有效,但在運行時無效。典型的例子是servlet-api,編譯和測試項目的時候需要該依賴,但在運行項目的時候,由於容器已經提供,就不需要Maven重複地引入一遍。
runtime: 運行時依賴範圍。
使用此依賴範圍的Maven依賴,對於測試和運行classpath有效,但在編譯主代碼時無效。典型的例子是JDBC驅動實現,項目主代碼的編譯只需要JDK提供的JDBC接口,只有在執行測試或者運行項目的時候才需要實現上述接口的具體JDBC驅動。
注意:以上四種範圍是開發中常用的配置,而以下兩種都是不要求的,使用的很少,瞭解即可
system: 系統依賴範圍。
該依賴與三種classpath的關係,和provided依賴範圍完全一致。但是,使用system範圍依賴時必須通過systemPath元素顯式地指定依賴文件的路徑。由於此類依賴不是通過Maven倉庫解析的,而且往往與本機系統綁定,可能造成構建的不可移植,因此應該謹慎使用。
import(Maven 2.0.9及以上): 導入依賴範圍。
總結
至此,對於Maven的依賴性已經講解差不多了,餘下的在開發中很少使用到,所以掌握以上內容已經足夠使用了,而且Maven的依賴算是Maven的學習中的一個難點,因此需要自己手動創建項目進行測試驗證。
在此,一樣恭祝大家學習愉快,新年快樂!