讓開發自動化: 利用 Ivy 管理依賴項

  轉自:http://www.ibm.com/developerworks/cn/java/j-ap05068/

讓開發自動化: 利用 Ivy 管理依賴項

使用公共存儲庫和 Apache Ant 共享其他項目的源代碼

級別: 初級

 

Paul Duvall ([email protected]), CTO, Stelligent Incorporated

2008 年 6 月 10 日

管理項目和工具之間的源代碼依賴項往往非常困難,但並不一定總是如此。在這一期“ 讓開發自動化 ”中,自動化專家 Parl Duvall 介紹瞭如何利用 Apache Ant 項目中的 Ivy 依賴項管理器來處理所有重要 Java 項目必須管理的無數依賴項。

實際上,所有軟 件開發項目都必須依靠來自其他項目的源代碼。例如,許多項目可能依靠 log4j 等日誌記錄工具和 Struts 之類的 Web 框架。您的開發團隊不會維護其他項目的源代碼,但要依靠其 API 來實現項目中的定製軟件。您的軟件所依靠的其他項目數量越多(包括這些項目自身的依賴項),構建軟件就變得越複雜。

關於本系列

作爲開發人員,我們致力於爲用戶自動化流程;但許多開發人員疏忽了自動化我們自己的開發流程的機會。爲此,我們編寫了 讓開發自動化 系列文章,專門探討軟件開發流程自動化的實踐應用,爲您介紹 何時 以及 如何 成功應用自動化。

我已經看到許多團隊使用各種不完善的技術,嘗試解決這種難題:

  • 將全部有依賴關係的項目(JAR 文件)放在一個目錄中,此目錄將簽入項目的版本控制存儲庫。這種技術不必要地增加了存儲庫的大小,使得管理版本差異極爲困難。
  • 將有依賴關係的 JAR 分配到一個公共文件服務器上,使團隊無法控制版本更改。
  • 手動將 JAR 文件複製到各開發人員工作站上的指定位置。這種方法使得確定丟失的文件或修正版本極爲困難。
  • 執行一條 HTTP Get 命令,將文件下載到開發人員的工作站,手動執行或將其作爲自動構建的一部分。這種技術會造成未受管理的 JAR 文件。

我參加過一箇中型項目,包含 1,000 個 Java 類和 100 多個有依賴關係的 JAR 文件。(我們選擇了第一種不完美的技術:將所有 JAR 簽入項目的版本控制存儲庫。)圖 1 顯示了可能在此類項目中看到的一小部分依賴項的類型:


圖 1. Web 開發項目中的 JAR 依賴項示例
Web 開發項目中的 JAR 依賴項示例

Transfixed on transitive dependencies

傳遞依賴(Transitive dependency) 是一個複雜的術語,但表示的是 Ivy 提供的一種簡單而強大的特性。某些 JAR 文件依賴於其他 JAR,這樣才能正常工作。使用 Ivy,您只需一次性聲明一個組件的依賴項。此後,僅需瞭解一個項目的主要 JAR 文件,而無需瞭解它的所有 JAR 文件依賴項。如果您體驗過手動查找依賴項的痛苦——無論是通過文檔還是通過研究代碼,您就會發現,此特性本身就值得您付出時間在項目中配置 Ivy。參見本文 依賴於依賴項 一節瞭解更多細節。

圖 1 表現出,Brewery 項目的源代碼依賴於 Hibernate、Struts 2、MySQL Connector 和 Cobertura。而 Cobertura 又依賴其他 JAR,如 asm-2.2.1.jar、jakarta-oro-2.0.8.jar 和 log4j-1.2.9.jar。此外,asm-2.2.1.jar 依賴 asm-tree-2.2.1.jar。這僅僅是可能出現的各類嵌套依賴項的一個簡單示例。即便是某個 JAR 的版本不正確,您也會體驗到難以排除的問題,例如編譯錯誤或意料之外的行爲。

Apache Maven 構建管理和項目管理工具已經吸引了 Java 開發人員的注意。Maven 引入了 JAR 文件公共存儲庫的概念,可通過公開的 Web 服務器訪問(稱爲 ibiblio)。Maven 的方法減少了 JAR 文件膨脹的情況,不會佔用大多數版本控制存儲庫。但使用 Maven 時,它會鼓勵您採用其 “慣例優於配置” 的方法來構建軟件,這會制約您定製構建腳本的靈活性。

如果您多 年來一直使用 Apache Ant,現在希望獲得使用公共存儲庫的優勢,又該如呢?您是否不得不接受 Maven 的構建方法來獲得這些收益?幸運的是,答案是否定的,這是由於一種稱爲 Apache Ivy 的工具 — Ant 的一個子項目。Ivy 提供了最一致、可重複、易於維護的方法,來管理項目的所有構建依賴項(在 參考資料 部分中可以找到 Maven 和 Ivy 的比較)。這篇文章介紹了安裝和配置 Ivy 來管理依賴項的基礎知識,指出了可參考的更多信息。

入門

開 始使用 Ivy 非常簡單,只需創建兩個 Ivy 特有的文件,添加一些 Ant 目標即可。Ivy 特有的文件是 ivy.xml 和一個 Ivy 設置文件。ivy.xml 文件中列舉了項目的所有依賴項。ivysettings.xml 文件(可以隨意爲此文件命名)用於配置從中下載有依賴關係的 JAR 文件的存儲庫。

清單 1 展示了一個簡單的 Ant 腳本,它調用了兩個 Ivy 任務:ivy:settingsivy:retrieve


清單 1. 使用 Ivy 的簡單 Ant 腳本

<target name="init-ivy" depends="download-ivy">
<ivy:settings file="${basedir}/ivysettings.xml" />
<ivy:retrieve />
</target>

 

清單 1 中,ivy:settings 定義了 Ivy 設置文件。對 ivy:retrieve 的調用從 ivy.xml 聲明的一個存儲庫中檢索 JAR 文件。

安裝 Ivy

下 載並使用 Ivy 的方法有幾種。第一種是手動將 Ivy JAR 文件下載到 Ant lib 目錄中,也可下載到 Ant 腳本的類路徑中定義的某個目錄中。我迷上了自動化,所以更傾向於使用自動化替代方案:下載 Ivy 的 JAR 文件,在 Ant 目標中配置類路徑。清單 2 展示了這種技術的示例:


清單 2. 使用 Ant 自動安裝 Ivy

<?xml version="1.0" encoding="iso-8859-1"?>
<project name="test-ivy" default="init-ivy" basedir="."
xmlns:ivy="antlib:org.apache.ivy.ant" xmlns="antlib:org.apache.tools.ant">
<property name="ivy.install.version" value="2.0.0-beta2" />
<property name="ivy.home" value="${user.home}/.ant" />
<property name="ivy.jar.dir" value="${ivy.home}/lib" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />

<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant" classpath="${ivy.jar.dir}/ivy.jar"/>

<target name="download-ivy">
<mkdir dir="${ivy.jar.dir}"/>
<get src="http://www.integratebutton.com/repo/
${ivy.install.version}/ivy-2.0.0-beta2.jar"
dest="${ivy.jar.file}" usetimestamp="true"/>
</target>

</project>

 

清單 2 中的第二行定義了 XML 名稱空間。antlib 在 ivy.jar 文件中引用 antlib.xml。其餘的 xmlns 指明瞭 ivy Ant 任務的完全限定路徑。${user.home}/.antivy.home 值是 ivy.jar 文件下載的目標位置。taskdef 定義了 ivy Ant 任務,引用其類路徑的位置。download-ivy 目標下載 ivy-2.0.0-beta2.jar 並使用 dest 屬性爲其重命名。

一旦下載並配置了 Ivy,就可以使用任意 Ivy Ant 任務(如 清單 1 中調用的兩個任務)。

創建配置腳本

ivy.xml 文件是必不可少的,您在此文件中定義項目的全部有依賴關係的 JAR。清單 3 展示了一個示例:


清單 3. 在 ivy.xml 中定義依賴項

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="./config/ivy/ivy-doc.xsl"?>
<ivy-module version="1.0">
<info organisation="com" module="integratebutton" />
<dependencies>
<dependency name="hsqldb" rev="1.8.0.7" />
<dependency name="pmd" rev="2.0" />
<dependency name="cobertura" rev="1.9"/>
<dependency name="checkstyle" rev="4.1" />
<dependency name="junitperf" rev="1.9.1" />
<dependency name="junit" rev="3.8.1" />
</dependencies>
</ivy-module>

 

請注意,清單 3 未表示任何文件位置或 URL,允許您轉到其他目錄位置,而無需更改依賴項列表。info 元素中的 organisation 屬性標識了組織類型(如 .net、.org 或 .com)。後接 module 名稱。此模塊的依賴項列表遵循一種命名規範,在下一個清單中您將更清晰地看出此規範。目前,只需記住 dependency name="cobertura" rev="1.9" 將轉換爲 cobertura-1.9.jar 即可。

清單 4 是 Ivy 設置文件的示例。它定義了 清單 3 中 ivy.xml 文件所用的存儲庫位置和相關模式。


清單 4. Ivy 設置文件

<ivysettings>
<settings defaultResolver="chained"/>
<resolvers>
<chain name="chained" returnFirst="true">
<filesystem name="libraries">
<artifact pattern="${ivy.conf.dir}/repository/[artifact]-[revision].[type]" />
</filesystem>
<url name="integratebutton">
<artifact pattern="http://www.integratebutton.com/repo/[organisation]/[module]/
[revision]/[artifact]-[revision].[ext]" />
</url>
<ibiblio name="ibiblio" />
<url name="ibiblio-mirror">
<artifact pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/
[module]/[branch]/[revision]/[branch]-[revision].[ext]" />
</url>
</chain>
</resolvers>
</ivysettings>

 

清單 4 中的 filesystem 元素定義了本地工作站上的位置模式。兩個 url 元素定義了可用於下載 JAR 文件的多個位置:第一個元素定義了受我控制的 integratebutton.com 上的一個自定義存儲庫;第二個元素定義了包含大量開源 JAR 文件的外部 Maven 存儲庫(不受我控制)。如果 Ivy 無法從第一個存儲庫下載 — 比如此存儲庫宕機,或者文件未在指定位置 — 它將嘗試第二個位置。優點在於,一旦 Ivy 下載了一個 JAR,它就會將文件置入您的本地文件系統,不必再爲每一次構建重新下載這些文件。

 




回頁首


依賴於依賴項

一個模塊常常要依賴其他模塊。例如,在 圖 1 中可以看到,cobertura-1.9.jar 文件的多個依賴項中包括 asm-2.2.1.jar,而 asm-2.2.1.jar 又依賴於 asm-tree-2.2.1.jar。如果沒有像 Ivy 這樣的工具,您就需要確保類路徑中存在這些 JAR 的正確版本,保證 JAR 版本之間不存在衝突。而使用 Ivy,您只需定義 cobertura 模塊及其所有依賴模塊,如清單 5 中所示的 ivy.xml 文件那樣。切記,這個 ivy.xml 文件與 cobertura-1.9.jar 文件位於同一目錄。


清單 5. 在 ivy.xml 文件中定義依賴項

<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
<info organisation="cobertura" module="cobertura" revision="1.9"/>
<configurations>
<conf name="master"/>
</configurations>

<publications>
<artifact name="cobertura" type="jar" conf="master" />
</publications>

<dependencies>
<dependency org="objectweb" name="asm" rev="2.2.1" conf="master"/>
<dependency org="jakarta" name="oro" rev="2.0.8" conf="master"/>
<dependency org="apache" name="log4j" rev="1.2.9" conf="master"/>
</dependencies>
</ivy-module>

 

清單 5 中特別強調的依賴項定義了 objectweb org 和名稱 asm 以及要使用的特定修訂版。Ivy 將此信息與 ivysettings.xml 文件中的存儲庫定義(如 清單 4 所示)一起使用,用於下載 JAR 文件的依賴項。

圖 2 展示了符合 清單 4 所示 ivysettings.xml 文件配置的存儲庫中的目錄結構:


圖 2. asm 模塊的目錄結構
asm 依賴項的目錄結構

請注意,圖 2 展示了一個 ivy.xml 文件(見清單 6),它定義了 asm 的依賴項。 在清單 6 中,針對 asm 模塊的 ivy.xml 文件片段表示了它惟一的依賴項 — asm-tree-2.2.1.jar:


清單 6. 爲 asm 定義依賴項的 ivy.xml

...
<dependencies>
<dependency org="objectweb" name="asm-tree" rev="2.2.1" conf="master"/>
</dependencies>
...

 

簡單說明一下,cobertura 模塊定義了三個依賴模塊:asmjakarta-orolog4j,如 清單 5 所示。而 asm 模塊又有一個依賴模塊,名爲 asm-tree,如 清單 6 所示。

請注意,圖 3 中的 asm-tree 目錄結構與 圖 2 中的 asm 模塊結構相似:


圖 3. asm-tree 模塊的目錄結構
asm-tree 模塊的目錄結構

當然,差別在於 JAR 文件包含不同的類,圖 2 所示的 ivy.xml 文件的定義描述了 asm-tree 模塊。(碰巧,asm-tree 模塊未在其 ivy.xml 文件中定義任何依賴項。)

 




回頁首


Ivy 進階

既然您已經掌握了使用 Ivy 的基本知識,下面我將介紹其他一些有用的 Ant 任務。

呈現報告

Ivy 提供了一個任務,用於報告一個項目中的依賴文件。清單 7 展示瞭如何調用 Ivy 的 report Ant 任務來創建依賴項列表:


清單 7. 通過 Ant 生成 Ivy 依賴項報告

<target name="ivy-report" depends="init-ivy">
<ivy:report todir="${target.dir}/reports/ivy"/>
</target>

 

清單 7 中的腳本生成了一份 HTML 報告,顯示了某項目的依賴文件列表。圖 4 展示了該報告:


圖 4. 顯示項目依賴項的 HTML 報告
Ivy 使用 Ant 生成的項目依賴項 HTML 報告

其他任務

還有其他許多針對 Ivy 的 Ant 任務可供您使用 — 通過爲 Maven 生成一個 POM 文件來清理本地文件系統緩存。表 1 顯示了部分 Ivy 的 Ant 任務及其用途:


表 1. 其他 Ivy Ant 任務

TaskPurpose
settings 對於驗證包含存儲庫的主機最有用
cachepath 覆蓋本地文件系統上的默認緩存路徑,所下載的文件將存放在此路徑中
repreport 爲存儲庫中的幾個模塊生成報告
install 安裝一個模塊及其所有依賴項
makepom 通過 ivy.xml 文件創建一個 pom.xml file,供 Maven 使用
cleancache 清理本地文件系統緩存,強制在下一次構建時從存儲庫重新檢索 JAR 文件

 

參見 參考資料,瞭解 Ivy 中可用的其他 Ant 任務。

 




回頁首


一切視情況而定

版本控制二進制庫

Ivy 並未 消除對 JAR 文件進行版本控制的需要。我常常看到有些團隊由於得到了可通過 HTTP 訪問的存儲庫,就徹底忘記了將文件置於版本控制系統之中。如果一年之後您需要重新創建軟件,而 HTTP 存儲庫未得到集中管理,重新創建的過程將十分艱難。使用可通過 HTTP 訪問的版本控制存儲庫(如 Subversion)將避免這樣的 窘境,因爲您可以集中管理 提供 HTTP 訪問

Ivy 集中管理依賴文件,消除了開發團隊將 JAR 文件從一個版本控制存儲庫複製到另一個存儲庫中時可能出現的膨脹現象。如果您正參與一個簡單的項目,將 JAR 文件簽入版本控制系統或使用本文開頭列出的其他某些技術可能不會顯著降低您的速度。但若您的項目規模越來越大,或者您在使用公共文件的企業環境中工作,一 種公共方法就變得十分必要。無論是哪種情況,Ivy 都能使定義項目依賴項更爲一致、更爲可行。因此值得您付出時間研究 Ivy 在您的項目中的應用。


參考資料

學習

  • 您可以參閱本文在 developerWorks 全球站點上的 英文原文
  • Apache Ivy:訪問 Ivy 項目網站,查看文檔、教程和社區資源。
  • "Ivy in 4.2 steps" (Andrew Glover,testearly.com,2007 年 6 月):通過幾個簡單的步驟使 Ivy 開始運行。
  • Ivy / Maven2 Comparison(Apache Ant Ivy 項目):Ivy 與 Maven 2 依賴項管理之間的差異探討。
  • Ant in Action (Steven Loughran 和 Erik Hatcher,Manning,2007年):這是一本出色的書籍,其中的第 11 章專門探討使用 Ivy 進行依賴項管理的內容。
  • 讓開發自動化 (Paul Duvall,developerWorks):閱讀整個系列文章。
  • 瀏覽 技術書店,查看關於上述和其他技術主題的書籍。
  • developerWorks Java 技術專區:數以百計的文章,介紹 Java 編程的所有方面。


獲得產品和技術

  • Ant:下載 Ant,開始以可預計、可重複的方式構建軟件。
  • Ivy:下載 Ivy。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章