maven工程导入项目打开404_Maven依赖配置和依赖范围
教程前面用坐標(biāo)一一對(duì)應(yīng)地描述了構(gòu)件,并且保存在倉(cāng)庫(kù)中了。那用坐標(biāo)描述好后,把它們放在倉(cāng)庫(kù)中的作用是什么呢?當(dāng)其他項(xiàng)目需要在這些構(gòu)件的基礎(chǔ)上做開發(fā)的時(shí)候,用戶就沒必要自己再重新實(shí)現(xiàn)一遍了。直接指定坐標(biāo),告訴?Maven?將坐標(biāo)對(duì)應(yīng)的構(gòu)件從倉(cāng)庫(kù)中找出來,集成到新項(xiàng)目中就可以了。這時(shí)候引入的構(gòu)件,就是新項(xiàng)目的依賴。依賴一般分以下兩個(gè)層次理解:1)在 Maven 項(xiàng)目的 pom.xml 中配置所需要構(gòu)件的坐標(biāo),也就是配置依賴。還有就是 Maven 在構(gòu)建項(xiàng)目的時(shí)候,根據(jù)坐標(biāo)從倉(cāng)庫(kù)中找到坐標(biāo)所對(duì)應(yīng)的構(gòu)件文件,并且把它們引入 Maven 項(xiàng)目中來,也就是 Maven 引用。2)由 Maven 構(gòu)建的時(shí)候自己搞定。前面也介紹了 Maven 基于坐標(biāo)尋找要執(zhí)行的插件的思路。實(shí)際上,插件本身就是一個(gè)特殊的構(gòu)件。查找插件的思路也就是依賴查找的思路。這里需要把握的更多的是第一層次,即怎樣配置依賴,以及指定依賴內(nèi)部的關(guān)系和優(yōu)化等。
依賴的配置
掌握依賴,從配置開始。接下來介紹一下依賴的配置。依賴是配置在 pom.xml 中的,如下是關(guān)于依賴配置的大概內(nèi)容:
<project> ... <dependencies> <dependency> <groupId>...groupId> <artifactId> ... artifactId> <version>...version> <type>...type> <scope>...scope> <optional>...optional> <exclusions> <exclusion>...exclusion> exclusions> dependency> ... dependencies> ...project>通過前面依賴配置樣例會(huì)發(fā)現(xiàn),依賴配置中除了構(gòu)件的坐標(biāo)信息、groupId、artifactId 和 version 之外,還有其他的元素。接下來就簡(jiǎn)單介紹一下這些元素的作用。
groupId、artifactId 和 version:依賴的基本坐標(biāo)。對(duì)于任何依賴,基本坐標(biāo)是最基本、最重要的,因?yàn)?Maven 是根據(jù)坐標(biāo)找依賴的。
type:依賴的類型,同項(xiàng)目中的 packaging 對(duì)應(yīng)。大部分情況不需要聲明,默認(rèn)是 jar。
scope:依賴的范圍,詳細(xì)情況后面介紹。
optional:標(biāo)記依賴是否可選,詳細(xì)情況后面介紹。
exclusions:排除傳遞性依賴,詳細(xì)情況后面介紹。
依賴的范圍
Java?中有個(gè)環(huán)境變量叫 classpath。JVM 運(yùn)行代碼的時(shí)候,需要基于 classpath 查找需要的類文件,才能加載到內(nèi)存執(zhí)行。Maven 在編譯項(xiàng)目主代碼的時(shí)候,使用的是一套 classpath,主代碼編譯時(shí)需要的依賴就添加到這個(gè) classpath 中去;Maven 在編譯和執(zhí)行測(cè)試代碼的時(shí)候,又會(huì)使用一套 classpath,這個(gè)動(dòng)作需要的依賴就添加到這個(gè) classpath 中去;Maven 項(xiàng)目具體運(yùn)行的時(shí)候,又有一個(gè)獨(dú)立的 classpath,同樣運(yùn)行時(shí)需要的依賴,肯定也要加到這個(gè) classpath 中。這些 classpath,就是依賴的范圍。依賴的范圍,就是用來控制這三種 classpath 的關(guān)系(編譯 classpath、測(cè)試 classpath 和運(yùn)行 classpath),接下來分別介紹依賴的范圍的名稱和意義。
1)compile
編譯依賴范圍。如果在配置的時(shí)候沒有指定,就默認(rèn)使用這個(gè)范圍。使用該范圍的依賴,對(duì)編譯、測(cè)試、運(yùn)行三種 classpath 都有效。
2)test
測(cè)試依賴范圍。使用該范圍的依賴只對(duì)測(cè)試 classpath 有效,在編譯主代碼或運(yùn)行項(xiàng)目的時(shí)候,這種依賴是無效的。
3)provided
已提供依賴范圍。使用此范圍的依賴,只在編譯和測(cè)試 classpath 的時(shí)候有效,運(yùn)行項(xiàng)目的時(shí)候是無效的。比如 Web 應(yīng)用中的 servlet-api,編譯和測(cè)試的時(shí)候就需要該依賴,運(yùn)行的時(shí)候,因?yàn)槿萜髦凶詭Я?servlet-api,就沒必要使用了。如果使用了,反而有可能出現(xiàn)版本不一致的沖突。
4)runtime
運(yùn)行時(shí)依賴范圍。使用該范圍的依賴,只對(duì)測(cè)試和運(yùn)行的 classpath 有效,但在編譯主代碼時(shí)是無效的。比如 JDBC 驅(qū)動(dòng)實(shí)現(xiàn)類,就需要在運(yùn)行測(cè)試和運(yùn)行主代碼時(shí)候使用,編譯的時(shí)候,只需 JDBC 接口就行。
5)system
系統(tǒng)依賴范圍。該范圍與 classpath 的關(guān)系,同 provided 一樣。但是,使用 system 訪問時(shí),必須通過 systemPath 元素指定依賴文件的路徑。因?yàn)樵撘蕾嚥皇峭ㄟ^ Maven 倉(cāng)庫(kù)解析的,建議謹(jǐn)慎使用。如下代碼是一個(gè)使用 system 范圍的案例。
<dependency> <groupId>xxxgroupId> <artifactId>xxxartifactId> <version>xxversion> <scope>systemscope> <systemPath>e:/xxxx/xxx/xx.jarsystemPath>dependency>6)import
導(dǎo)入依賴范圍。該依賴范圍不會(huì)對(duì)三種 classpath 產(chǎn)生實(shí)際的影響。它的作用是將其他模塊定義好的 dependencyManagement 導(dǎo)入當(dāng)前 Maven 項(xiàng)目 pom 的 dependencyManagement 中。比如有個(gè)?SpringPOM Maven 工程,它的 pom 中的 dependencyManagement 配置如下:
<project> ... <groupId>cn.com.mvn.pomgroupId> <artifactId>SpringPOMartifactId> <version>0.0.1-SNAPSHOTversion> <packaging>pompackaging> ... <dependencyManagement> <dependencies> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-coreartifactId> <version>${project.build.spring.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-aopartifactId> <version>${project.build.spring.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-beansartifactId> <version>${project.build.spring.version}version> dependency> dependencies> dependencyManagement> ...project>接下來創(chuàng)建一個(gè)新的 Maven 工程 Second,要將 First 工程中 pom 中定義的 dependency-Management 原樣合并過來,除了復(fù)制、繼承之外,還可以編寫如下代碼,將它們導(dǎo)入進(jìn)去。
<dependencyManagement> <dependencies> <dependency> <groupId>cn.com.mvn.pomgroupId> <artifactId>SpringPOMartifactId> <version>0.0.1-SNAPSHOTversion> <type>pomtype> <scope>importscope> dependency> dependencies>dependencyManagement>傳遞性依賴
在使用 Maven 之前,如果要基于 Spring 框架開發(fā)項(xiàng)目,除了要加入 Spring 框架的 jar 包外,還需要將 Spring 框架所用到的第三方 jar 包加入。否則編譯通過,但是運(yùn)行的時(shí)候就會(huì)出現(xiàn) classNotFound 異常。為了解決這種問題,一般有兩種方式:一種是下載 Spring 的 dependencies.zip 包,將其中的所有 jar 包都導(dǎo)入工程;另一種是根據(jù)運(yùn)行時(shí)的報(bào)錯(cuò)信息,確定哪些類沒有,再將包含這些類的 jar 包下載下來導(dǎo)入。第一種方式雖然可以一次性解決所有需要 jar 包的導(dǎo)入問題,但是當(dāng)查看工程的 jar 包會(huì)發(fā)現(xiàn),有不少多余的 jar 包。這些多余的 jar 包不僅僅加大了項(xiàng)目的體積,還有可能同其他框架所導(dǎo)入的 jar 包有版本沖突。第二種方式雖然不會(huì)有多余的 jar 包存在,但是要根據(jù)每次啟動(dòng)的錯(cuò)誤,一個(gè)個(gè)找到 jar 包,再導(dǎo)入。想象如果有 10 個(gè) jar 包,就要啟動(dòng) 10 次,查看 10 次錯(cuò)誤分別導(dǎo)入,有多麻煩。Maven 的傳遞依賴機(jī)制就能解決這樣的問題。當(dāng)項(xiàng)目基于 Spring 框架實(shí)現(xiàn)的時(shí)候,只需將 Spring 的依賴配置到 pom 的依賴元素就行。至于 Spring 框架所依賴的第三方 jar 包,用戶不用處理,Maven 自己通過檢測(cè) Spring 框架的依賴信息將它們導(dǎo)入項(xiàng)目中來。而且只會(huì)導(dǎo)入 Spring 框架所需要的,不會(huì)導(dǎo)入多余的依賴。也就是說,Maven 會(huì)解析項(xiàng)目中的每個(gè)直接依賴的 pom,將那些必要的間接依賴以傳遞依賴的形式引入項(xiàng)目中。當(dāng)然,傳遞依賴在將間接依賴引入項(xiàng)目的過程中也有它自己的規(guī)則和范圍。這個(gè)規(guī)則和范圍是同前面介紹的依賴范圍緊密關(guān)聯(lián)的?,F(xiàn)在有三個(gè)項(xiàng)目(A、B 和 C 項(xiàng)目),假設(shè) A 依賴 B,B 依賴 C,這樣把 A 對(duì) B 的依賴叫第一直接依賴,B 對(duì) C 的依賴叫第二直接依賴,而 A 對(duì) C 的依賴叫傳遞依賴(通過 B 傳遞的)。中間 A 到 B 第一直接依賴的范圍和 B 到 C 第二直接依賴的范圍,就共同決定了 A 到 C 的傳遞依賴范圍。它們的影響效果,就如表 1 所示。坐標(biāo)第一列表示第一直接依賴的范圍,第一行表示第二直接依賴的范圍,中間的交叉點(diǎn)為共同影響后的傳遞依賴的范圍。
表 1 依賴的傳遞依賴compiletestprovidedruntimeCompilecompile----runtimetesttest----testprovidedprovided--providedprovidedruntimeruntime--?--runtime
表 1 依賴的傳遞依賴compiletestprovidedruntimeCompilecompile----runtimetesttest----testprovidedprovided--providedprovidedruntimeruntime--?--runtime通過前面的表格,可以得出如下規(guī)律。
當(dāng)?shù)诙苯右蕾嚍?compile 的時(shí)候,傳遞依賴同第一直接依賴一致。
當(dāng)?shù)诙苯右蕾嚍?test 的時(shí)候,沒有傳遞依賴。
當(dāng)?shù)诙苯右蕾嚍?provided 的時(shí)候,值將第一直接依賴中的 provided 以 provided 的形式傳遞。
當(dāng)?shù)诙苯右蕾嚍?runtime 的時(shí)候,傳遞依賴的范圍基本上同第一直接依賴的范圍一樣,但 compile 除外,compile 的傳遞依賴范圍為 runtime。
依賴的調(diào)解
在使用 Maven 自動(dòng)提供的傳遞依賴后,可以解決對(duì)應(yīng)的依賴管理,特別是間接依賴管理中遇到的問題。但是,當(dāng)多個(gè)直接依賴都帶來了同一個(gè)間接依賴,而且是不同版本的間接依賴時(shí),就會(huì)引起重復(fù)依賴,甚至包沖突的問題。那么,Maven 在傳遞依賴的時(shí)候是按什么規(guī)則來的呢?
1. 依賴調(diào)解原則
Maven 依賴調(diào)解原則有兩個(gè):一個(gè)是路徑優(yōu)先原則;另一個(gè)是聲明優(yōu)先原則。當(dāng)路徑優(yōu)先原則搞不定的時(shí)候,再使用聲明優(yōu)先原則。比如有個(gè)項(xiàng)目 A,它有兩個(gè)依賴:A→B→C→T(1.0),A→D→T(2.0)。會(huì)發(fā)現(xiàn),A 最終對(duì) T(1.0)和 T(2.0)都有間接依賴。這時(shí)候 Maven 會(huì)自動(dòng)判斷它的路徑,發(fā)現(xiàn) T(2.0)的路徑長(zhǎng)度為 2,T(1.0)的路徑長(zhǎng)度為 3,以最短路徑為原則,將 T(2.0)引入當(dāng)前項(xiàng)目 A。如果有個(gè)項(xiàng)目 A,它有兩個(gè)依賴:A→B→T(1.0),A→C→T(2.0)。這時(shí)候兩條路徑都是一樣的長(zhǎng)度 2,那 Maven 到底把哪個(gè)引入項(xiàng)目 A 呢?這時(shí)候 Maven 會(huì)判斷哪個(gè)依賴在 pom.xml 中先聲明,選擇引入先聲明的依賴。
2.可選依賴
在實(shí)際項(xiàng)目中,存在一些比較特殊的依賴。比如數(shù)據(jù)訪問層模塊對(duì)數(shù)據(jù)庫(kù)驅(qū)動(dòng)的依賴就比較特殊了。DAO 層要訪問數(shù)據(jù)庫(kù)的時(shí)候,需要加入數(shù)據(jù)庫(kù)驅(qū)動(dòng)依賴,而且不同數(shù)據(jù)庫(kù)驅(qū)動(dòng)依賴是不一樣的。如果在設(shè)計(jì) DAO 層的時(shí)候,是按跨數(shù)據(jù)庫(kù)標(biāo)準(zhǔn)實(shí)現(xiàn)的,這就引出了一個(gè)新問題,是在 pom.xml 中配置?MySQL?驅(qū)動(dòng)依賴呢?還是配置 Oracle 驅(qū)動(dòng)依賴?或者兩個(gè)都配置?其實(shí)仔細(xì)想想,前面三種選項(xiàng)都不合適。單獨(dú)配置 MySQL 或 Oracle,這樣就不能跨數(shù)據(jù)庫(kù)了。兩個(gè)數(shù)據(jù)庫(kù)都配置,驅(qū)動(dòng)之間就會(huì)有沖突,或有多余的依賴。這時(shí)候,就直接把這兩個(gè)數(shù)據(jù)庫(kù)驅(qū)動(dòng)的依賴都設(shè)置成可選依賴,代碼如下:
<dependencies> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>5.1.34version> <optional>trueoptional> dependency> <dependency> <groupId>oraclegroupId> <artifactId>ojdbc14artifactId> <version>10.2.0.4version> <optional>trueoptional> dependency>dependencies>在應(yīng)用項(xiàng)目中再具體指定使用哪個(gè)依賴,例如:
<dependencies> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>5.1.34version> dependency>dependencies>需要說明的是,在實(shí)際項(xiàng)目中建議不要使用可選依賴。雖然可選依賴滿足了對(duì)一個(gè)模塊的特征多樣性,同時(shí)還提供了更多的選擇,但是在實(shí)際配置中,好像不僅沒有減少配置代碼,還增多了重復(fù)復(fù)制的機(jī)會(huì)。
同時(shí)從面向?qū)ο蠓治龊驮O(shè)計(jì)的思路來說,也是建議遵循單一職責(zé)原則,也就是一個(gè)類只有一個(gè)功能,不要糅合太多的功能,這樣不方便理解、開發(fā)和維護(hù)。所以實(shí)際項(xiàng)目中,一般對(duì)不同數(shù)據(jù)庫(kù)的驅(qū)動(dòng)單獨(dú)創(chuàng)建一個(gè) Maven 工程。其他項(xiàng)目需要基于哪個(gè)數(shù)據(jù)庫(kù)進(jìn)行操作的話,引用對(duì)應(yīng)的 Maven 的工程以來就行,用傳遞依賴引入需要的數(shù)據(jù)庫(kù)驅(qū)動(dòng)依賴。
總結(jié)
以上是生活随笔為你收集整理的maven工程导入项目打开404_Maven依赖配置和依赖范围的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vscode 显示多个文件_优秀的 VS
- 下一篇: 剪裁tiff影像数据_能看更会用,超擎影