让开发自动化: 利用 Ivy 管理依赖项
http://www.ibm.com/developerworks/cn/java/j-ap05068/index.html
實際上,所有軟件開發項目都必須依靠來自其他項目的源代碼。例如,許多項目可能依靠 log4j 等日志記錄工具和 Struts 之類的 Web 框架。您的開發團隊不會維護其他項目的源代碼,但要依靠其 API 來實現項目中的定制軟件。您的軟件所依靠的其他項目數量越多(包括這些項目自身的依賴項),構建軟件就變得越復雜。
關于本系列
作為開發人員,我們致力于為用戶自動化流程;但許多開發人員疏忽了自動化我們自己的開發流程的機會。為此,我們編寫了 讓開發自動化 系列文章,專門探討軟件開發流程自動化的實踐應用,為您介紹 何時以及 如何成功應用自動化。
我已經看到許多團隊使用各種不完善的技術,嘗試解決這種難題:
- 將全部有依賴關系的項目(JAR 文件)放在一個目錄中,此目錄將簽入項目的版本控制存儲庫。這種技術不必要地增加了存儲庫的大小,使得管理版本差異極為困難。
- 將有依賴關系的 JAR 分配到一個公共文件服務器上,使團隊無法控制版本更改。
- 手動將 JAR 文件復制到各開發人員工作站上的指定位置。這種方法使得確定丟失的文件或修正版本極為困難。
- 執行一條 HTTP Get命令,將文件下載到開發人員的工作站,手動執行或將其作為自動構建的一部分。這種技術會造成未受管理的 JAR 文件。
我參加過一個中型項目,包含 1,000 個 Java 類和 100 多個有依賴關系的 JAR 文件。(我們選擇了第一種不完美的技術:將所有 JAR 簽入項目的版本控制存儲庫。)圖 1 顯示了可能在此類項目中看到的一小部分依賴項的類型:
圖 1. 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:settings和 ivy:retrieve。
清單 1. 使用 Ivy 的簡單 Ant 腳本
| <target name="init-ivy" depends="download-ivy"> <ivy:settingsfile="${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" /> <taskdefresource="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指明了 ivyAnt 任務的完全限定路徑。${user.home}/.ant的 ivy.home值是 ivy.jar 文件下載的目標位置。taskdef定義了 ivyAnt 任務,引用其類路徑的位置。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模塊的目錄結構
請注意,圖 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模塊定義了三個依賴模塊:asm、jakarta-oro和 log4j,如 清單 5所示。而 asm模塊又有一個依賴模塊,名為 asm-tree,如 清單 6所示。
請注意,圖 3 中的 asm-tree目錄結構與 圖 2中的 asm模塊結構相似:
圖 3. asm-tree模塊的目錄結構
當然,差別在于 JAR 文件包含不同的類,圖 2 所示的 ivy.xml 文件的定義描述了 asm-tree模塊。(碰巧,asm-tree模塊未在其 ivy.xml 文件中定義任何依賴項。)
回頁首
Ivy 進階
既然您已經掌握了使用 Ivy 的基本知識,下面我將介紹其他一些有用的 Ant 任務。
呈現報告
Ivy 提供了一個任務,用于報告一個項目中的依賴文件。清單 7 展示了如何調用 Ivy 的 reportAnt 任務來創建依賴項列表:
清單 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 任務可供您使用 —通過為 Maven 生成一個 POM 文件來清理本地文件系統緩存。表 1 顯示了部分 Ivy 的 Ant 任務及其用途:
表 1. 其他 Ivy Ant 任務
| 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。
討論
- Improve Your Code Quality 論壇:developerWorks 的杰出專欄作者 Andrew Glover 以顧問的身份在此論壇中貢獻他豐富的專業技術,主要關注改進代碼質量的問題。
- Accelerate development space:developerWorks 的杰出專欄作者 Andrew Glover 運作的一站式門戶,包含開發人員測試、持續集成、代碼度量和重構等內容。
- 訪問 developerWorks blog,加入 developerWorks 社區。
關于作者
Paul Duvall 是 Stelligent Incorporated 的 CTO,該公司是一家咨詢公司,在幫助開發團隊優化 Agile 軟件產品方面被認為是同行中的翹楚。他是 Addison-Wesley Signature 系列書籍 Continuous Integration: Improving Software Quality and Reducing Risk (Addison-Wesley,2007 年)的作者之一。他對 UML 2 Toolkit (Wiley,2003 年)和 No Fluff Just Stuff Anthology (Pragmatic Programmers,2007 年)也有貢獻。
http://blog.csdn.net/daquan198163/article/details/4768152 有了Ivy的幫忙,我們不需要為了一個庫依賴管理而舍棄Ant去學那個難搞的Maven了。基本配置步驟如下:
1、copy Ivy插件(org.apache.ivy_2.1.0.cr1_20090319213629.jar )到ant_home/lib下;
2、在項目根目錄下新建ivysettings.xml ;
3、在項目根目錄下新建ivy.xml ,內容根據項目需要來;
4、修改你原來的build.xml,如下:
[xhtml:nogutter] view plaincopyprint?
完整的build.xml示例見http://code.google.com/p/smartpagination/source/browse/trunk/build.xml
Over!
至此,你已經為螞蟻插上了Ivy的翅膀,下面的工作只是錦上添花而已——在Eclipse配置Ivy,這個工作的作用是把ivy.xml變成classpath的一部分,使得我們只需要維護ivy.xml不需要維護.classpath文件。
配置步驟:
1、Window->preference->ant->RunTime->Classpath->Ant Home Entries,
右邊Add External Jars,添加org.apache.ivy_2.1.0.cr1_20090319213629.jar。
2、安裝Ivy插件:Help->Install new software->add,
Name: IvyDE,Location: http://www.apache.org/dist/ant/ivyde/updatesite
安裝成功后重啟eclipse;
3、重啟eclipse后,Window->preference->ivy->settings
Ivy settings path設為d:/workspace/ivysettings.xml(這個值取決于你的環境)
至此,Eclipse的ivy插件配置好了,然后就可以為你的項目classpath添加ivy依賴了:
選中項目->右鍵 屬性->Java Build Path->Libraries->Add Library...->IvyIDE Managed Dependencies->finish->OK
然后神奇的事情就出現了——雖然你一個jar包也沒下載,只是在ivy.xml里面聲明了一下,但是你的項目已經可以編譯通過了,就好像那些第三方類庫已經在你本地了一樣。
?
總結
以上是生活随笔為你收集整理的让开发自动化: 利用 Ivy 管理依赖项的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Netty 简单样例分析(io传输的框架
- 下一篇: access violation at