前言:在Java的世界中扳缕,【包】是最基本的結構,因此包管理就是Java項目中的一件特別重要的事情。本文介紹的就是Java世界中的包管理躯舔,以及最流行的包管理工具Maven驴剔。
Java的包管理
要介紹Java的包管理,我們就要先知道什么是包:
包管理中的【包】指的是什么粥庄?
-
首先丧失,我要知道JVM(Java Virtual Machine,即Java虛擬機)的工作原理惜互。實際上布讹,JVM的工作被設計的相當簡單:
- 執(zhí)行一個類的字節(jié)碼
- 假如這個過程中碰到了新的類,就加載它训堆,然后執(zhí)行第一個步驟
-
那么描验,我們從哪兒加載這些類呢?
答案是【class path】
在IDEA中蔫慧,我們執(zhí)行了一段程序挠乳,在界面的下方权薯,我們沒有注意到的一段灰色的代碼姑躲,里面就藏著classpath
idea界面
在這段命令中,-classpath 或者 -cp后面接的就是這段程序找包的地方盟蚣。
類的全限定類名(目錄層級)唯一確定了一個類
包黍析,就是把許多類放在一起打的壓縮包
包的傳遞性依賴
- 何為傳遞性依賴,即:你依賴的類還依賴了別的類
- 于是屎开,恐怖的事情發(fā)生了:classpath hell(依賴地獄)
- 全限定類名是類的唯一標識
- 如果阐枣,我引用了A包和B包,B包中又引用了A包奄抽,就會出現(xiàn)多個同名類(A包)出現(xiàn)在classpath中蔼两,這就是下文即將說到的【包沖突】
- 如果出現(xiàn)了包沖突,默認的解法就是:優(yōu)先使用classpath排在前面的包逞度。
- pom.xml (pom额划,就是Project Object Model)就是一份項目的說明書,看了pom.xml就知道這個項目是如何工作的档泽。
什么是包管理
簡單來說包管理的本質就是下面三點:
- 你要使用一些第三方類俊戳,總要告訴JVM從哪里找吧?
- 包管理的本質就是告訴JVM如何找到所需的第三方類庫
- 以及成功的解決其中的沖突問題
Maven的包管理
Apache Maven馆匿,是一個軟件(特別是Java軟件)項目管理及自動構建工具抑胎,由Apache軟件基金會所提供〗ケ保基于項目對象模型(縮寫:POM)概念阿逃,Maven利用一個中央信息片斷能管理一個項目的構建、報告和文檔等步驟。
Maven是一個劃時代的成就恃锉,必須強調羽历,Maven遠遠不止是包管理工具,還是一個自動化構建工具淡喜。Java在經歷了很多年的發(fā)展后秕磷,Maven的應運而生,是我們在龐大的Java項目中管理包不再是一件令人頭疼的事情炼团。
Maven —— 劃時代的包管理
- Maven的中央倉庫(即遠程倉庫)澎嚣,按照一定的約定存儲包,我們可以在中央倉庫中瘟芝,找到所有的已經發(fā)布了的包易桃,用于我們查找及下載。
- Maven的本地倉庫锌俱,默認位于
~/.m2
晤郑,下載的第三方包放在這里緩存 - 而Maven最優(yōu)秀的地方就是,它規(guī)定了每一個包的命名規(guī)范贸宏,按照這種約定造寝,我們就能方便的在中央倉庫找到不同團隊、不同版本的包吭练,在項目中诫龙,也可以確定的引入我們想要引入的包。而Maven的命名規(guī)范主要是按照以下三個維度:
- groupId / artifactId / version
groupid
和artifactId
被統(tǒng)稱為“坐標”是為了保證項目唯一性而提出的鲫咽,如果你要把你項目弄到maven本地倉庫去签赃,你想要找到你的項目就必須根據(jù)這兩個id去查找。
groupId
一般分為多個段分尸,這里我只說兩段锦聊,第一段為域,第二段為公司名稱箩绍。域又分為org孔庭、com、cn等等許多伶选,其中org為非營利組織史飞,com為商業(yè)組織。舉個apache公司的tomcat項目例子:這個項目的groupId是org.apache仰税,它的域是org(因為tomcat是非營利項目)构资,公司名稱是apache,artifactId是tomcat陨簇。
比如我創(chuàng)建一個項目吐绵,我一般會將
groupId
設置為cn.enoch
迹淌,cn表示域為中國,enoch
是我的名字己单,artifactId
設置為testProj
唉窃,表示你這個項目的名稱是testProj
,依照這個設置纹笼,你的包結構最好是cn.enoch.testPro
打頭的纹份,如果有個StudentDao
,它的全路徑就是cn.enoch.testProj.dao.StudentDao
拓展:語義化版本
5.0.0-M1 【milestone 里程碑】
5.0.0-RC1 【Release candiate廷痘,正式版本的候選版本】
alpha:內部版本
beta:公測版本
SNAPSHOT:快照版本蔓涧,用于開發(fā)聯(lián)調的包
Maven 包沖突及解決
什么是包沖突
簡單的來說就是因為傳遞性依賴導致某一個包被引入了兩次,在classpath中出現(xiàn)了兩次笋额,從而導致我們在運行Java程序時元暴,classpath中后出現(xiàn)的那次引入的包不會被引入到項目中來。
包沖突可能會出現(xiàn)的異常
- AbstractMethodError
- NoClassDefFoundError
- ClassNotFoundException
- LinkageError
Maven傳遞性依賴的自動管理:
- 原則:絕不允許最終的classpath出現(xiàn)同名不同版本的jar包
- 依賴沖突的解決原則:最近的勝出
遠兄猩,還是近茉盏?
上圖中,最終形成的classpath枢冤,【C0.2】會被舍棄鸠姨,即,包沖突導致我們被迫使用了低版本的jar包
怎么解決呢掏导?
- 首先:需要理清項目中的依賴關系享怀,找到哪一個依賴因為maven自動給舍棄導致的問題
- 然后可能需要去看一下這個包的不同版本的源碼羽峰,找到為什么maven自動舍棄一些包依賴后會報異常(比如上面的例子:高版本被舍棄趟咆,但是我們用到了高版本才有的方法)
- 解決它(兩種解法)
- 在我的項目中,直接依賴【C0.2】版本梅屉,這樣maven就會選擇最近的【C0.21】值纱,即在項目pom中直接引入該版本包的dependency。
-
排除掉【D包】的傳遞性依賴坯汤,這樣我們的依賴樹就只有一個【C0.2】包了 虐唠。使用exclusions,排除掉D包依賴的C包惰聂。
exclusions的用法
如果兩個發(fā)生沖突的包”距離“一樣呢疆偿?
這張圖搓幌,【C0.1】和【C0.2】具體相同杆故,那么maven為了保證classpath同名包只有一個,就會選擇最先聲明的包溉愁,舍棄后者(比如先依賴的A处铛,就會選擇C0.1)
Maven的其他知識
scope
- 依賴的scope(指定依賴只在scope中有效),實現(xiàn)依賴的隔離
- compile/test/provided等等
- main 生產代碼 / test 測試代碼
- 最重要的有三個:(test / compile / provided)
-
<scope>test</scope>
只有在測試代碼中(@TEST)才看得到這個包,在main里面無法使用這個包 -
<scope>compile</scope>
在main和test都可見撤蟆,即編譯時候可見奕塑,運行時候可見,測試代碼可見家肯,生產代碼可見 -
<scope>provided</scope>
只在編譯的時候有效龄砰,運行的時候就無效了,即只把這個包用于編譯讨衣。- 編譯:把源代碼變成字節(jié)碼的過程
- 運行:jvm加載字節(jié)碼并開始運行的過程
- NoClassDefFoundError
- tomcat
比如你的代碼經過編譯以后要部署到tomcat容器中寝贡,tomcat容器會幫你添加一些第三方依賴包,為了防止包沖突值依,我們就需要把這些包設置成provided
-
Maven查看依賴樹
-
mvn dependency:tree
展示的是解決沖突后的依賴樹 - 在idea中看
- 安裝maven helper插件
pom文件中圃泡,選擇dependency analyzer --》all dependencies as tree
(完)