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