自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

漫談依賴管理工具:從Maven,Gradle到Go

運維 系統(tǒng)運維
本文從Maven談起,分析了Maven的主要思想以及Gradle對Maven的改進,最后談了下Go語言面臨的依賴管理問題。

為什么要有依賴管理工具?

  談依賴管理之前,我們先談?wù)劄槭裁匆幸蕾嚬芾砉ぞ哌@東西。

  我們學(xué)了一種編程語言,然后寫了個“Hello World”,然后宣稱自己學(xué)了一門語言,這時候確實不需要關(guān)心依賴問題。

  然而,當(dāng)你要寫一個稍微復(fù)雜點的應(yīng)用,那怕就是留言板這樣的,需要讀寫數(shù)據(jù)庫,就需要依賴數(shù)據(jù)庫驅(qū)動,就會遇到依賴管理的問題了。

  再進一步,你寫了一個庫,想共享給別人使用,更需要了解依賴管理的問題。

  當(dāng)然,如果項目足夠簡單,你可以直接將依賴方的源碼放置在自己的項目中,或者將依賴庫的二進制文件(比如jar,dll)放置在項目的lib里。要提供給別人呢?把二進制包提供下載或者給別人傳過去。依賴管理工具出現(xiàn)之前大多數(shù)都是這樣搞的。

  但如果再復(fù)雜些,依賴庫本身也有依賴怎么弄呢?將依賴壓縮打包,然后放個readme幫助文件說明下,貌似也可以工作。

  那如果你的項目依賴了好幾個,乃至幾十個庫,而各庫又有依賴,依賴也有自己的依賴,怎么辦?怎么檢測庫的依賴是否有版本沖突?以后升級的時候怎么辦?怎么判斷l(xiāng)ib目錄下的某個文件是否被依賴了?

  到這一步必須要承認(rèn)需要有個依賴管理工具了,無論你使用任何語言。我們大約也清楚了依賴管理要做些什么。假設(shè)還沒有依賴管理工具,我們自己要設(shè)計一個,如何入手?

  1.要有一種依賴庫的命名規(guī)則,或者叫坐標(biāo)(Coordinates)的定義規(guī)則,可以通過坐標(biāo)準(zhǔn)確找到依賴的庫。

  2.要有對應(yīng)的配置文件規(guī)則,來描述和定義依賴。

  3.要有中心倉庫保存這些依賴庫,以及依賴庫的元數(shù)據(jù)(metadata),供使用方拉取。

  4.還需要一個本地工具去解析這個配置文件,實現(xiàn)依賴的拉取。

  以上其實就是各依賴管理工具的核心要素。

  聊聊Maven

  Maven誕生于2004年(來源維基),查詢了下,應(yīng)該是各語言的依賴管理工具中早的。Ruby的gem也是2004年出現(xiàn)的,但gem離完備的依賴管理工具還差些,直到Ruby的bundler出現(xiàn)。Python的pip出現(xiàn)的更晚。

  Maven的習(xí)慣是通過 groupID(一般是組織的域名倒寫,遵循Java package的命名習(xí)慣)+ artifactId(庫本身的名稱) + version(版本)來定義坐標(biāo),通過xml來做配置文件,提供了中心倉庫(repo.maven.org)以及本地工具(mvn)?! ?/p>

  1. 依賴定義: 
  2.  
  3.   <dependency>  
  4.   <groupId>com.google.guava</groupId>  
  5.   <artifactId>guava</artifactId>  
  6.   <version>18.0</version>  
  7.   </dependency> 
  8.  
  9. repo定義: 
  10.  
  11.   <repository>  
  12.   <id>repo.default</id>  
  13.   <name>Internal Release Repository</name 
  14.   <url>http://repo.xxxxxx.com/nexus/content/repositories/releases</url>  
  15.   <releases>  
  16.   <enabled>true</enabled>  
  17.   <updatePolicy>interval:60</updatePolicy>  
  18.   <checksumPolicy>warn</checksumPolicy>  
  19.   </releases>  
  20.   <snapshots>  
  21.   <enabled>false</enabled>  
  22.   <updatePolicy>always</updatePolicy>  
  23.   <checksumPolicy>warn</checksumPolicy>  
  24.   </snapshots>  
  25.   </repository> 

  同時,為了避免依賴沖突的問題,Maven的依賴配置提供了exclude配置機制,用于阻斷部分庫的傳遞依賴。

  Ruby的gem,Node的npm,Python的pip,iOS的CocoaPods都類似,只是配置文件語法和坐標(biāo)命名規(guī)則有些差異。

  至此,看起來Maven很簡單??!為啥許多人會覺得Maven復(fù)雜呢?

  主要在于以下兩點:

  1.Java這樣需要編譯的語言,發(fā)布的庫是二進制版本的jar包,發(fā)布前需要有編譯的流程,而依賴和編譯是緊密相關(guān)的。不像Ruby,Node這樣的腳本語言,將源碼和配置文件扔到倉庫就可以。

  2.Maven并沒有將自己單純的定義為依賴管理工具,而是項目管理工具,它將項目的整個生命周期都囊括進去了。

  第二點也是Ant+ivy和Maven思路上的區(qū)別,ivy認(rèn)為已經(jīng)有Ant這樣的編譯打包工具了,只需在上面做個插件解決依賴問題即可,而Maven認(rèn)為Ant本身也有改進的地方,所以一并改造了。

  Maven的改進的核心思路是:Convention Over Configuration

  即“約定大于配置”。既然大多數(shù)人習(xí)慣都把源碼目錄命名為src,那就約定好都用這個目錄,不用專門去配置。同樣,clean,compile,package等也約定好,不需要專門定義Ant task。這樣既簡化了配置文件,同時也降低了學(xué)習(xí)成本。一個Ant定義的項目,你需要閱讀幫助文件或者查看build.xml文件才能了解如何編譯打包,而Maven定義的項目直接運行“mvn package”即可。

  Java語言發(fā)明的比較早,初期這種思想還不普及,所以Java本身沒有對項目的規(guī)范,而新的語言基本都吸收了這個思想,對項目都做了約定和規(guī)范。比如Go語言,如果用C/C++可能需要定義復(fù)雜的Makefile來定義編譯的規(guī)則,以及如何運行測試用例,而在Go中,這些都是約定好的。

  Maven定義為項目管理工具,包含了項目從源碼到發(fā)布的整個生命周期:  

  1. validate → generate-sources → process-sources  
  2.   → generate-resources → process-resources → compile  
  3.   → process-classes → generate-test-sources  
  4.   → process-test-sources → generate-test-resources  
  5.   → process-test-resources → test-compile  
  6.   → test → prepare-package → package  
  7.   → pre-integration-test → integration-test  
  8.   → post-integration-test → verify → install → deploy 

  既然包含了這么多功能和階段,所以Maven引入了插件機制,Maven本身的編輯打包等功能都是用插件來實現(xiàn)的,也允許用戶自己定義插件。

  同時涉及構(gòu)建生命周期的不同的階段,依賴也需要確定是編譯依賴?測試依賴?運行時依賴?于是依賴多了scope的定義。

  如果僅僅是這樣把Maven理解成標(biāo)準(zhǔn)化的Ant+ivy+可擴展的插件框架即可?但現(xiàn)實世界的項目往往更復(fù)雜。

  我們有了function用于組合代碼塊邏輯,有了object用于組合一組方法,有了package,namespace用于組合一組相關(guān)對象,但其實還需要有更高一個層次的組合定義 —– module,或者叫子項目。同一個項目下,不同的源碼目錄可能需要編譯打包成不同的二進制文件,這些module共同構(gòu)成了一個整體的項目。這個其實和源碼管理習(xí)慣有關(guān)系,是每個獨立的module作為單獨的源碼倉庫呢?還是將相關(guān)的module全部放在一起?從降低溝通成本的角度考慮,還是應(yīng)該通過一個大的倉庫組織。

  于是Maven引入了module的概念,同一個項目下可以有多個module,每個module有單獨的pom文件來定義,但為了避免重復(fù),Maven的pom文件支持parent機制,子項目的pom文件繼承parent pom的基本配置。可以說,module的機制將Maven的復(fù)雜度又提升了一個層次,很多人遇到Maven的坑多栽到這里了。

  這里介紹一個Maven多項目版本管理的***實踐:

  1.父項目中配置版本號,子項目中不要顯示配置版本號,直接繼承父項目的版本號。

  2.子項目之間的依賴通過${project.version}引用,不要明確配置版本號。

  3.發(fā)布新版的時候,同時發(fā)布所有子項目,即便是該子項目未做變更。

  4.***通過Maven的release插件發(fā)布,避免手動修改版本號導(dǎo)致的不一致問題。

  即便是這樣,Maven的多項目版本管理經(jīng)常也會遇到問題。主要是因為Maven的子項目之間的依賴也沿用的是第三方庫依賴的配置方式,需要指定子項目的版本號。另外子項目的parent需要顯式配置,也需要明確指定parent的版本號。一旦這些版本號出現(xiàn)錯誤,***就會導(dǎo)致各種詭異的問題。

  Maven的release插件使用也比較復(fù)雜,該插件其實做幾個事情:

  1.先構(gòu)建一遍項目,確認(rèn)項目可以正常構(gòu)建。

  2.修改pom文件的版本號到正式版,然后提交到源碼倉庫并打tag。

  3.將該tag的源碼檢出,再構(gòu)建一次,這次構(gòu)建的jar包的版本是正式版的,將jar包上傳到Maven倉庫。

  4.遞增版本號,修改pom文件的版本號到SNAPSHOT,再次提交到源碼倉庫。

  這個過程中,由于要構(gòu)建兩次,提交兩次源碼倉庫,上傳一次jar包,任何一步出錯都會導(dǎo)致release失敗,所以使用比較復(fù)雜。

  到此,Maven的核心概念都分析完了,其他的都是插件機制上的一些擴展。大家也應(yīng)該明白了Maven之所以***變這么復(fù)雜的原因。

  但無論如何,Maven基本上是項目管理工具的標(biāo)桿了,有的語言直接通過擴展插件來用Maven管理,比如C++,C#(NMaven),或者做了移植Byldan(C#),不過貌似都是不太成功,估計主要原因應(yīng)該是Maven是用Java寫的,有社區(qū)隔膜。

  Gradle對Maven的改進

  聊了Maven的思路和優(yōu)勢,那Maven的缺點呢?這個我們和Gradle一起聊聊。Gradle就是在Maven的基礎(chǔ)上進行的改進。優(yōu)勢主要體現(xiàn)在以下方面:

  1.配置語言

  Maven使用的是XML,受限于XML的表達能力以及XML本身的冗余,會使pom.xml文件顯得冗長而笨重。而Gradle是基于Groovy定義的一種DSL語言,簡潔并且表達能力強大。在Maven中,任何擴展都需要通過Maven插件實現(xiàn),但Gradle的配置文件本身就是一種語言,可以直接依賴任意Java庫,可以直接在build.gradle文件中像Ant一樣定義task,比Ant的表達能力更強(Ant本身也是XML定義的)。

  Gradle的配置文件中可以直接獲取到Project對象以及環(huán)境變量,可以通過程序?qū)uild過程進行更細(xì)致的自定義控制,這個功能對于復(fù)雜的項目來說非常有用。

  2.項目自包含(Self Provisioning Build Environment)

  用戶下載了一個Maven定義的項目,如果沒用過Maven,還需要下載Maven工具包,了解Maven。但Gradle可以給項目生成一個 gradlew腳本,用戶直接運行g(shù)radlew腳本即可,該腳本會自動檢測本地是否已經(jīng)有Gradle,沒有則從網(wǎng)絡(luò)下載,對用戶透明(當(dāng)然,國內(nèi)網(wǎng)絡(luò)下***還是自己先下載好)。

  對倉庫的配置,Maven提供了一個本地的settings.xml配置文件,用于定義私有倉庫以及倉庫密碼這樣敏感的不應(yīng)該放源碼倉庫里的文件。但這樣帶來的不便就是這些信息項目中沒有自包含,所以Gradle干掉了這種本地配置的機制,所有的定義都在項目里。私有倉庫密碼這樣的可以放在項目下的 gradle.properties文件里不提交上去,通過其他方式分享給內(nèi)部成員。這點可能各有優(yōu)劣。

  3.任務(wù)依賴以及執(zhí)行機制

  Maven的構(gòu)建生命周期的每一步都是預(yù)定義好的(參看前文),插件任務(wù)只能在預(yù)留的生命周期中的某個階段切入,雖然Maven的生命周期階段考慮很充分,但有時候也不能滿足需求。Maven會嚴(yán)格按照生命周期的階段從開始線性執(zhí)行任務(wù),而Gradle則使用了Directed Acyclic Graph來檢測任務(wù)的依賴關(guān)系,決定哪些任務(wù)可以并行執(zhí)行,這樣使任務(wù)的定義以及執(zhí)行都更靈活。

  4.依賴管理更為靈活

  Maven對依賴管理比較嚴(yán)格,依賴必須是源碼倉庫的坐標(biāo)。雖然也支持system scope的本地路徑配置,但還是有許多不方便之處(system scope的依賴,打包的時候不包含進來)。如果世界上所有的庫都通過Maven發(fā)布,當(dāng)然沒有問題,但現(xiàn)實往往不是這樣的。這里要吐槽一下國內(nèi)的各大廠發(fā)布的sdk之類的庫,幾乎都不提供倉庫地址,就給個壓縮包放一堆jar包進來,讓用戶自己搞定依賴管理問題。而Gradle在這方面比較靈活,比如支持:  

  1. compile fileTree(dir: 'libs', include: '*.jar'

  這樣的配置規(guī)則。

  另外由于Gradle本身是一種語言,可以用編程的方式來管理依賴。比如大多數(shù)子項目都依賴某個庫,除了個別幾個,就可以這樣寫:

 

  1. configure(subprojects.findAll {it.name != 'xxx1’ && it.name != ‘xxx2’}) {  
  2. dependencies {  
  3. compile("com.google.guava:guava:18.0”)  
  4.  

  5.子項目以及動態(tài)依賴機制

  動態(tài)依賴主要是用來解決幾個互相依賴的庫都在快速開發(fā)期間的依賴問題,不能每次地層庫修改發(fā)布新版本,上層庫都要修改依賴配置文件,所以需要動態(tài)設(shè)置依賴***版本。

  Maven的解決方案是SNAPSHOT機制,子項目之間也是通過這個機制來實現(xiàn)依賴的。遇到的問題我們前面也分析了。

  Gradle的雖然也兼容Maven倉庫的SNAPSHOT機制,但它自己的版本管理機制上,并沒有引入SNAPSHOT機制。它的依賴支持4.x,2.+這樣的配置規(guī)則,實現(xiàn)動態(tài)依賴(注:Maven也支持類似的規(guī)則,參看 Dependency Version Requirement Specification)。而子項目之間的依賴采用特殊的依賴配置,和第三方庫的配置規(guī)則有區(qū)別。它直接使用:  

  1. compile project(“:subpoject-name”); 

  這樣的配置,無需配置版本號,明確指定是子項目,避免Maven的子項目依賴帶來的版本號問題。子項目的配置中也不需要顯示配置父項目,只需要父項目單向中配置子項目列表即可。

  同時Gradle的release機制也更為靈活,支持release到各種倉庫(包括Maven倉庫),但不控制release過程中的版本號生成,修改源碼倉庫等步驟,留給用戶自己通過手動或者CI工具,或者腳本去解決。

  關(guān)于Gradle相對Maven的改進這里主要列舉這幾點,其他的可以參看Gradle官方的比較表格:maven_vs_gradle,這里不再詳述。

  Go語言的多項目以及依賴管理問題

  ***再談?wù)凣o語言的多項目以及依賴管理問題。Go官方對這兩方面并未做約定或者提供工具,于是只能各自想辦法解決。多項目問題一般就是回歸到了 Makefile+腳本的解決方案,比如kubernetes。依賴管理,開源社區(qū)多用Godeps,kubernetes用的也是這個。Godeps通過源碼倉庫路徑以及源碼tag來確定庫的坐標(biāo),只管理依賴,有點像ivy,不關(guān)心構(gòu)建過程。Godepes會將依賴庫的依賴也添加到當(dāng)前項目的依賴配置中,不是動態(tài)的依賴傳遞機制。沒有scope,不區(qū)分是否是單元測試的依賴。一個倉庫只支持一個配置,沒有子項目概念,項目大了管理就比較復(fù)雜。另外它對傳遞依賴以及版本沖突的問題當(dāng)前還是沒有解決太好(有一些相關(guān)Issue)。

  一個語言的多項目以及依賴管理方案對這個語言的生態(tài)發(fā)展有很大的影響,Java發(fā)展到現(xiàn)在,Maven以及Gradle功不可沒,所以感覺Go官方應(yīng)該對這兩方面有所作為。Go語言遲遲沒出依賴管理工具,個人覺得有幾方面考慮:

  1.Go尚未確定動態(tài)庫的機制。編譯型語言依賴***也是二進制的,而不是源碼。一方面可以加快編譯速度,另外一方面也可以實現(xiàn)源碼保護,方便分發(fā)以及代理緩存,讓語言的適用范圍更廣。許多商業(yè)上的庫是不方便提供源碼的。所以依賴管理工具的實現(xiàn)需要動態(tài)庫的機制。而動態(tài)庫尚未確定的原因我覺得是Go 語言不想過早的引入二進制動態(tài)庫的格式兼容問題,初期全部用源碼是最省事的。

  2.先讓社區(qū)試試水,看看效果和反饋。

  任何一個語言,發(fā)展到一定階段都避不開依賴管理問題。前一段時間看到一篇寫Go語言的文章,嘲諷Java的Maven構(gòu)建個項目恨不能把半個互聯(lián)網(wǎng)下載下來,我當(dāng)時腦海中就浮現(xiàn)出長者的那句經(jīng)典語錄“圖樣圖森破”。Go當(dāng)前沒遇到這些問題的原因只是Go還比較年輕,庫還不夠豐富,以及Go的很多項目還不夠復(fù)雜。而像kubernetes這樣的項目,當(dāng)前依賴已經(jīng)有226個了,構(gòu)建一下,也快要下載半個Github了。所以個人覺得Go社區(qū)當(dāng)前還是非常需要一個類似于Gradle的工具,來解決依賴管理,構(gòu)建,多項目管理等問題。

責(zé)任編輯:火鳳凰 來源: 午夜咖啡
相關(guān)推薦

2017-02-27 08:37:01

2023-09-04 13:26:27

PHP開發(fā)工具

2011-08-12 10:38:09

MongoDB

2009-04-24 21:13:45

服務(wù)器虛擬化Vmware

2012-12-06 11:31:40

虛擬化

2020-09-30 14:05:22

網(wǎng)絡(luò)管理

2020-10-30 11:18:47

網(wǎng)絡(luò)技術(shù)工具

2012-04-09 09:43:49

云計算云管理

2013-07-17 09:54:17

2013-07-15 15:00:26

項目管理工具

2014-03-28 11:15:42

phpmyadminMySQL管理

2012-03-01 10:04:02

虛擬化云計算混合云

2021-03-04 12:55:01

systemd進程管理工具Linux

2022-08-03 08:02:46

PDM工具Python

2022-05-06 12:04:24

Ansible管理工具

2023-03-07 14:21:57

2022-06-16 11:06:07

開源Grafanaon-call

2010-05-25 18:36:54

MySQL管理工具

2009-05-21 10:38:51

MySQLphpMyAdminSun

2021-01-14 15:41:22

LinuxSupervisor命令
點贊
收藏

51CTO技術(shù)棧公眾號