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