沒有Maven之前的日子個人的一個小感受,學(xué)習(xí)一個新技術(shù),應(yīng)該以歷史的眼光開看待這個新技術(shù)出現(xiàn)的原因,以及幫我們解決了什么問題。我們來回憶一下沒有Maven的日子是怎么樣的?
這時(shí)候Maven作為Java世界的包管理工具出現(xiàn)了,當(dāng)然Java世界還有其他包管理工具,例如gradle等。就像yum是Linux世界的包管理工具,webpack是前端世界的包管理工具一樣 Maven倉庫的種類Maven找jar包的過程是這樣的,先在本地倉庫找,找不到再去私服(如果配置了的話),再找不到去中央倉庫(http://repo1./maven2/,maven團(tuán)隊(duì)負(fù)責(zé)維護(hù)) 從中央倉庫找到后,會在私服和本地倉庫放一份,從私服找到后也會在本地倉庫放一份 當(dāng)你安裝在好了Maven以后,在conf目錄下有個settings.xml文件,這個里面配置的項(xiàng)很多,后文會詳細(xì)介紹這個配置文件。 <!-- localRepository | The path to the local repository maven will use to store artifacts. | | Default: ${user.home}/.m2/repository <localRepository>/path/to/local/repo</localRepository> --> 在這個配置文件下有這樣一段話,說了Maven默認(rèn)的本地倉庫地址為${user.home}/.m2/repository(當(dāng)然你可以重新設(shè)置本地倉庫的地址,上面就是模板),我是window電腦,來看看這個目錄 看到有很多jar包被存到本地,當(dāng)然如果你想配置私服也是在settings.xml上進(jìn)行配置,隨便一搜很多教程,不再贅述 搭建私服好處多多,在一個公司內(nèi)部可以開發(fā)一些公共的基礎(chǔ)組件放到私服上,方便其他同事使用 Maven的默認(rèn)配置一個Maven的項(xiàng)目的整體結(jié)構(gòu)是這樣的 為什么一個Maven項(xiàng)目的文件結(jié)構(gòu)是這種的呢? 這就不得不說到Maven的一個特性,約定優(yōu)于配置。 Maven默認(rèn)配置了${project.basedir}/src/main/java為項(xiàng)目的源代碼目錄 ${project.basedir}/src/main/test為項(xiàng)目的測試代碼目錄 ${project.basedir}/target為項(xiàng)目的編譯輸出目錄等 spring boot就是約定優(yōu)于配置的體現(xiàn),想想我們用spring mvc的時(shí)候還得配置視圖解析器,包的自動掃描,而用了spring boot框架,我們就完全不用再配置了 Maven項(xiàng)目詳解安裝還是挺簡單的,我就不再介紹,我也沒有單獨(dú)下載,一般就用了Idea自帶的Maven了,下載完后目錄結(jié)構(gòu)如下: bin目錄: 該目錄包含了mvn運(yùn)行的腳本,這些腳本用來配置java命令,準(zhǔn)備好classpath和相關(guān)的Java系統(tǒng)屬性,然后執(zhí)行Java命令。 boot目錄: 該目錄只包含一個文件,該文件為plexus-classworlds-2.5.2.jar。plexus-classworlds是一個類加載器框架,相對于默認(rèn)的java類加載器,它提供了更加豐富的語法以方便配置,Maven使用該框架加載自己的類庫。 conf目錄: 該目錄包含了一個非常重要的文件settings.xml。直接修改該文件,就能在機(jī)器上全局地定制maven的行為,即對所有用戶都生效。一般情況下,我們更偏向于復(fù)制該文件至~/.m2/目錄下(~表示用戶家目錄,windows下~就是C:UsersPeng,Peng是小編的用戶名),然后修改該文件,在用戶級別定制Maven的行為。 lib目錄: 該目錄包含了所有Maven運(yùn)行時(shí)需要的Java類庫,Maven本身是分模塊開發(fā)的,因此用戶能看到諸如maven-core-3.0.jar、maven-model-3.0.jar之類的文件,此外這里還包含一些Maven用到的第三方依賴如commons-cli-1.2.jar、commons-lang-2.6.jar等等。、 settings.xml配置文件詳解我們來詳細(xì)說一下settings.xml這個文件,這個文件可以定制Maven的行為,上面已經(jīng)說到settings.xml可以放在2個位置,~/.m2/setting.xml(默認(rèn)沒有,需要我們自己復(fù)制)和${maven.home}/conf/setting.xml 這2個配置文件的加載順序?yàn)閪/.m2/setting.xml>${maven.home}/conf/setting.xml,為了不影響他人,所以我們將conf下的settings.xml復(fù)制到家目錄,在用戶級別定制Maven的行為。 這個和配置環(huán)境變量有點(diǎn)類似,Windos和Linux都可以配置系統(tǒng)級別的環(huán)境變量和用戶級別的環(huán)境變量,這里單說一下Linux的吧,在/etc/profile里面配置的就是系統(tǒng)級別的環(huán)境變量,在~/.bash_profile里面配置的就是用戶級別的環(huán)境變量 各種配置項(xiàng)還是挺多的,設(shè)置鏡像倉庫(國內(nèi)用阿里云的比較多),設(shè)置代理,不再贅述 maven常用命令
當(dāng)然也可以連著使用 mvn clean package 清理打包 mvn clean package -DskipTests=true 清理打包,并跳過測試用例 mvn clean install 清理打包,并將jar包或者war包復(fù)制到本地倉庫 運(yùn)行單測的時(shí)候也沒必要一個一個點(diǎn)測試方法,mvn test 一個命令跑完所有測試用例, 要注意的是只會執(zhí)行以Test開頭或者結(jié)尾的測試類,也沒必要自己寫測試類,我在推薦閱讀第一篇文章中演示了快速生成測試類的方法,可以去看看,生成的測試類都是以Test結(jié)尾的 mvn dependency:tree > show.txt 將依賴輸出重定向到文件中,方便查看 pom.xml詳解groupId 公司域名倒過來 artifactId 功能命名 version 版本號 這三個維度確定一個jar包,就像用(x,y,z)坐標(biāo)在三維空間中唯一確定一個點(diǎn)。 packaging 打包方式,jar,war,maven-plugin(開發(fā)maven插件) scope詳解
類似如下這種,沒有指定scope,說明scope是compile <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> test是指在運(yùn)行測試用例的時(shí)候才會用到,沒必要打入到最后的jar里面,所以你看到的測試框架的scope基本上都是test <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> provided,編譯的時(shí)候會用到,但不會被打入最后的jar包 例如想把spring boot項(xiàng)目以war包的形式放在tomcat中運(yùn)行,首先得加入如下依賴 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> 或者你寫了一個放在Storm集群或者Flink集群上運(yùn)行的任務(wù),最后都要把Storm的依賴或者Flink的依賴設(shè)置成provided,因?yàn)榧荷弦呀?jīng)都有這些環(huán)境的jar包、 如果你用到lombok插件的話,你會發(fā)現(xiàn)lombok的Maven是如下形式,說明它只會編譯的時(shí)候會用到。 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.6</version> <scope>provided</scope> </dependency> 我寫了如下一個測試類 @Data public class Test { private String name; private int age; } 生成的class文件反編譯后的如下,驗(yàn)證了我們的想法,編譯之后確實(shí)沒有必要再用lombok這個jar包 public class Test { private String name; private int age; public Test() { } public String getName() { return this.name; } public int getAge() { return this.age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } } runtime,運(yùn)行時(shí)才會用到。例如,如果你的項(xiàng)目有對數(shù)據(jù)庫的操作,但沒有加入相應(yīng)的JDBC的實(shí)現(xiàn)jar包,如mysql-connector-java,是可以編譯成功的,只有運(yùn)行時(shí)才會報(bào)錯。所以你看到的JDBC實(shí)現(xiàn)的jar包scope為runtime,表明這個jar包在運(yùn)行時(shí)才會用到 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.35</version> <scope>runtime</scope> </dependency> system,本地加載jar,當(dāng)你和第三方公司合作,他們只是給了你一個jar包時(shí),你可以有三種選擇
<dependency> <groupId>com.tievd.third</groupId> <artifactId>arcvideo</artifactId> <version>1.0</version> <scope>system</scope> <systemPath>${basedir}/lib/face-api-1.0.jar</systemPath> </dependency> 前文已經(jīng)說到scope為system的依賴不會被打入最終的jar包,得通過配置插件等方式將依賴打入最終的jar包,所以這種方式一般很少使用。 Maven jar包沖突如何解決? 依賴傳遞假設(shè)我們現(xiàn)在有一個多模塊項(xiàng)目,依賴關(guān)系如圖,我們在st-web模塊中引入st-dal依賴時(shí),st-common-lib這個依賴也會被我們引入,這個就是依賴傳遞,下表中列出了scope在依賴過程中發(fā)生的變化,列標(biāo)題為被依賴的模塊的scope
依賴仲裁依賴仲裁就是當(dāng)項(xiàng)目中引入的jar包,groupId (公司域名倒過來)和artifactId (功能命令)一樣,但是version不一樣,應(yīng)該選用哪一個version?也經(jīng)常被人叫做依賴沖突 最短路徑原則 假如說我們現(xiàn)在的項(xiàng)目依賴關(guān)系如圖?那么maven會選用st-common-lib的那個版本呢? 答案是1.1這個版本,st-web到st-common-lib(1.1)的距離為1,st-web到st-common-lib(1.0)的距離為2,選擇距離短的,即最短路徑原則 如何看依賴的距離關(guān)系呢?前文說過,執(zhí)行如下命令打印出全局的依賴樹,層級關(guān)系特別清楚 mvn dependency:tree > show.txt 聲明優(yōu)先原則 項(xiàng)目依賴如圖,路徑一樣,會選用st-common-lib的哪個版本呢?這就得看你在pom文件中先聲明是哪個依賴,如果在pom.xml中,st-remote-invoker寫在前面,就會用1.0這個版本,如果st-dal寫在前面,則會用1.1這個版本 依賴排除去掉間接引入的jar包 如不想用spring boot默認(rèn)提供的log,想集成第三方的log時(shí),或者說上面依賴仲裁的第二個例子中,只想用st-common-lib的1.1版本,就可以把1.0版本排除掉 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> (完) |
|