| Perl語(yǔ)言的發(fā)明人Larry Wall曾經(jīng)把懶惰稱(chēng)為是程序員的一種“美德”,我想如果你是具備這樣一種“美德的程序員,一定不會(huì )對“代碼自動(dòng)生成”這一概念等閑視之,看看Eclipse上著(zhù)名的Lomboz插件以及開(kāi)源社區廣為流行的AndroMDA吧,它們就是基于這種“代碼自動(dòng)生成”的產(chǎn)物。如果你恰巧是具備了這種“美德”的Java程序員,那么XDoclet將是你所夢(mèng)寐以求的工具。
代碼自動(dòng)生成和XDoclet 的由來(lái)
在軟件開(kāi)發(fā)的歷史中,代碼自動(dòng)生成的思想并不是一個(gè)很時(shí)髦的概念了,XDoclet同樣也不是唯一的代碼自動(dòng)生成工具,我們所熟悉的IDE開(kāi)發(fā)環(huán)境中的代碼向導,甚至流行的JSP技術(shù)(也不過(guò)就是從JSP自動(dòng)生成servlet)等等,這種讓程序來(lái)寫(xiě)代碼的思想比比皆是。定義一個(gè)代碼生成要求規范作為代碼自動(dòng)生成的輸入——代碼生成器讀入這個(gè)抽象的要求規范,然后借助于模板,輸出一個(gè)或多個(gè)符合那個(gè)抽象要求規范的輸出文件,這就是代碼生成的大體流程。主要有主動(dòng)式和被動(dòng)式兩種類(lèi)型的碼生成方式,兩者的區別在于代碼生成在開(kāi)發(fā)過(guò)程中所扮演的角色。在被動(dòng)式的代碼生成方式中,代碼被一次性生成并由開(kāi)發(fā)者來(lái)編輯修改生成的結果輸出文件(例如IDE中的代碼向導);與此相反,在主動(dòng)式的代碼生成方式中,開(kāi)發(fā)者需要編輯并修改的是代碼生成器的輸入文件而不是生成的輸出文件,兩者的區別是顯而易見(jiàn)的。本文介紹的XDoclet工具屬于主動(dòng)式的代碼生成方式。 XDoclet 最初源于數年前Rickard Oberg在為JBoss應用服務(wù)器開(kāi)發(fā)EJB容器的時(shí)侯,自稱(chēng)具備懶惰“美德”的Oberg發(fā)現為每個(gè)EJB組件編寫(xiě)大量的接口和部署描述符實(shí)在是一個(gè)巨大的負擔,并由此開(kāi)了一個(gè)稱(chēng)為EJBDoclet的工具,這就是XDoclet的前身。
什么是XDoclet?
XDoclet是一個(gè)開(kāi)放源碼的、可擴展的、元數據驅動(dòng)的、面向屬性(Attribute Oriented Programming)的Java代碼生成引擎,它使Java具備了面向屬性編程的能(Java通過(guò)XDoclet具備了.NET吹噓的“屬性”功能)。這意味著(zhù)你可以憑借在Java源代碼中附加元數據這種方式來(lái)為你的代碼添加更多的重要特性,這里所說(shuō)的元數據其實(shí)就是屬性,通過(guò)特定的JavaDoc 標簽把屬性添加到代碼中,XDoclet將對你的源代碼進(jìn)行解析,并依據那些元數據生成諸如XML格式的部署描述符、接口一些文件或其他的源代碼。當然,在生成過(guò)程中還需要借助于一些模板,模板利用提供在源代碼中以及JavaDoc 標簽中的信息來(lái)具體生成輸出文件。XDoclet雖然建立在EJBDoclet思想的基礎上,但適用范圍不再局限于EJB,現在我們已經(jīng)可以用XDoclet生成Web Service、部署描述符,甚至還可以對它進(jìn)行擴展,滿(mǎn)足自己的特殊需要。 一個(gè)XDoclet標簽通常由如下幾部分組成: @namespace.tag-name attribute-name="attribute value" 從概念上看與一個(gè)XML元素非常相似,都具有標簽名和可選的一系列屬性,不同之處是語(yǔ)法上的差異。標簽依據名稱(chēng)空間(namespace)分組,并且在那個(gè)名稱(chēng)空間中有一個(gè)唯一的名字。標簽可以有零個(gè)或多個(gè)屬性,并且按照名字=“值”對這種方式分割。這里簡(jiǎn)單解釋一下名稱(chēng)空間的作用,名稱(chēng)空間是用來(lái)確保名字不發(fā)生沖突的一種機制,常用的名稱(chēng)空間包括:ejb、web、jboss、weblogic、struts等等,它把相關(guān)的標簽進(jìn)行了分組。此外,標簽的值可以被指定為Ant屬性,如下代碼所示: @jboss.create-table create="${jboss.create.table}" 其中jboss.create.table就是一個(gè)在A(yíng)nt項目中定義的屬性。標簽一般存在于類(lèi)和方法這一層次(在極少數情況下也可以存在于類(lèi)的數據屬性字段和構造方法這一層次)。一個(gè)一般化的原則是:如果從類(lèi)的名字或類(lèi)型可以確定信息,就沒(méi)有必要用標簽來(lái)專(zhuān)門(mén)指定那個(gè)信息了。 一個(gè)典型的XDoclet標簽實(shí)例如下所示: * @ejb.bean 注意:上述例子中包含了3個(gè)部分:注釋、javadoc標簽和XDoclet標簽。其中頭兩個(gè)部分是標準的注釋文檔,并沒(méi)有因為使用了XDoclet而影響了它們本身正常功能的使用,第三個(gè)部分才是我們真正感興趣的部分。
XDoclet 的任務(wù)、子任務(wù)和模板
雖然XDoclet起源于一個(gè)創(chuàng )建EJB的工具,但是目前已經(jīng)逐漸發(fā)展為一個(gè)通用的代碼生成引擎,XDoclet由一個(gè)內核和數量不斷增長(cháng)的模塊(也就是XDoclet模板)組成,如果有針對某種新組件的需求,開(kāi)發(fā)一個(gè)新模塊是相當簡(jiǎn)單的工作。下面我們就來(lái)分別看看XDoclet的幾個(gè)核心概念:任務(wù)、子任務(wù)和模板。 XDoclet 任務(wù) 這里所謂的任務(wù)指的是在XDoclet中可用的高層次的代碼生成功能,或者也可以說(shuō)是核心的功能化模塊。每個(gè)這樣的任務(wù)關(guān)注于某一個(gè)特定的技術(shù)領(lǐng)域,下面列出主要的XDoclet 任務(wù): <ejbdoclet> <webdoclet> <hibernatedoclet> <jdodoclet> <jmxdoclet> <doclet> <documentdoclet> 其中<ejbdoclet>是到目前為止應用最為廣泛的XDoclet任務(wù),其次用得最多的就是<webdoclet>任務(wù)。 子任務(wù) 這里所謂的子任務(wù)就是由一個(gè)特定任務(wù)所提供的單一目的的代碼生成過(guò)程,一個(gè)XDoclet任務(wù)就是這些關(guān)注于某一個(gè)領(lǐng)域的、更為細化的一系列子任務(wù)的集合。任務(wù)對相關(guān)的子任務(wù)進(jìn)行管理和分組,并由子任務(wù)執行具體的代碼生成。舉例來(lái)說(shuō),當你要生成EJB組件時(shí),你需要為每個(gè)bean生成一個(gè)home接口、一個(gè)remote接口以及一個(gè)e j b - j a r . x m l 部屬描述符,這些就是<ejbdoclet>任務(wù)中的三個(gè)獨立的代碼生成子任務(wù)。 模板(Template) 模板就是包含一些代碼以及用于生成最終源代碼的、類(lèi)似XML形式的語(yǔ)法文件,模板文件中包含了通用的Java關(guān)鍵字以及由類(lèi)似XML標簽組成的一些結構,這些標簽結構便于XDoclet從輸入的源文件中獲取相關(guān)的信息。XDoclet利用模板這樣一種設計使得你可以非常容易的編寫(xiě)自己的特定模板,在你的代碼中找到重復的部分,然后編寫(xiě)特定的XDoclet模板來(lái)自動(dòng)生成它們,從而使XDoclet具有很強的可擴展性。 與Ant 的集成 XDoclet 是借助于A(yíng)nt 之類(lèi)的build 工具并作為build過(guò)程的一個(gè)部分來(lái)使用的,XDoclet的任務(wù)也是作為Ant build的任務(wù)來(lái)執行的(如左圖所示),目前Ant已成為事實(shí)上的Java標準構建工具。在使用XDoclet任務(wù)之前,首先需要用A n t 的<taskdef>來(lái)聲明一下,下述代碼在A(yíng)nt中聲明了一個(gè)<ejbdoclet>任務(wù): <taskedf name= “ejbdoclet” 其中classname和classpathref屬性告知Ant工具何處來(lái)定位實(shí)現這個(gè)任務(wù)的XDoclet類(lèi),詳細內容在下面使用XDoclet”一節具體介紹。 安裝XDoclet XDoclet可以運行在裝有Java 2 運行環(huán)境的任何平臺上,到目前為止XDoclet 已經(jīng)被成功的用于包括Linux、UNIX、Windows 9x、NT、2000 、XP和MacOSX等許多平臺。首先你必須確認JDK 的lib目錄下tools.jar 文件已經(jīng)正確的設置到classpath中,并且使用的是Jakarta Ant 1.5 以上版本(XDoclet不支持以前的版本)。安裝過(guò)程非常簡(jiǎn)單,只需從SourceForge 下載最新的XDoclet版本(xdoclet-bin-1.2.1版),解壓到你指定的目錄下即可,解壓后會(huì )看到在XDoclet目錄下有docs、lib 和samples 三個(gè)子目錄。 使用XDoclet 這里我們通過(guò)一個(gè)具體的實(shí)例來(lái)詳細介紹XDoclet的使用方法,XDoclet的使用其實(shí)是非常簡(jiǎn)的,就像給你的代碼添加JavaDoc 注釋一樣,只不過(guò)這里添加的是XDoclet標簽。XDoclet標簽是作為元數據提供者來(lái)使用的,元數據被用來(lái)生成所要求的輸出文件。 在開(kāi)始使用XDoclet之前,首先必須確定你希望用XDoclet來(lái)生成什么?最常用的兩個(gè)任務(wù)是ejbdoclet和webdoclet。通常情況下你需要為Ant定義XDoclet 任務(wù)、設置配置參數(如下例所示): <path id="project.class.path"> <entitycmp/> 在這個(gè)例子中compile target(編譯目標)依賴(lài)于ejbdoclet target,這里所說(shuō)的依賴(lài)的意思是:在編譯任何東西以前,所有的home、local、remote 接口, 主鍵, 數據對象和部署描述符統統已被生成。當然,你首先要做的就是為Ant定義這個(gè)ejbdoclet任務(wù)。為此需要用到taskdef標簽,在這個(gè)標簽里指定了xdoclet.modules.ejb.EjbDocletTask作為實(shí)現ejbdoclet 任務(wù)的類(lèi)。注意:標簽里的屬性classpathref指向標識為“project.class.path”的路徑,這個(gè)路徑包含所有的XDoclet jar和commons-logging.jar文件。下一步需要用一系列配置參數和嵌套的元素來(lái)聲明ejbdoclet 任務(wù),正如你所見(jiàn),這里也可以使用繼承機制,可以為每一個(gè)嵌套元素(或者也可以稱(chēng)為子任務(wù))重載destdir屬性參數。元素<deploymentdescriptor/>就重載了destdir屬性,重新定義了生成的ejb-jar.xml文件的存放位置。缺省情況下,每一個(gè)任務(wù)都有自己的內置的子任務(wù),其中有些是強制性的,例如<remoteinterface/>和<localinterface/>,你能想象出一個(gè)沒(méi)有remote 或localEJB 2.0 ) 接口的EJB嗎?其它的一些則是可選的,例如<jboss/>,你當然可以有其它的應用服務(wù)器選擇。還有第三種形式的子任務(wù):<template/>。這在你要設計自己的模板來(lái)生成定制的文件時(shí)是非常有用的,因此,你需要一種簡(jiǎn)單的方式以使XDoclet來(lái)使用你的模板。如下例所示: <taskdef <include name="**/*Bean.java"/> 這樣你就可以在任務(wù)中放置< template />元素標簽,并指定你自己的模板文件路徑和輸出文件名(存儲在destdir屬性指定的目錄中)。這一特性對于那些想要充分發(fā)揮XDoclet的性能定義自己的@tag(元素標簽)和模板的具有創(chuàng )造性的開(kāi)發(fā)者來(lái)說(shuō)是非常有用的。
XDoclet 帶給我們的益處
目前XDoclet的發(fā)行包中綁定的模塊支持幾乎所有的主流應用服務(wù)器,包括:JBoss、 BEA WebLogic、IBM WebSphere、Oracle IAS、 Orion、Borland、MacroMedia JRun、Jonas、Pramati和Sybase EAServer等等;支持的工具和框架包括:Castor、Hibernate、JDO、Struts、WebWork和MockObjects等等流行的工具和框架。這為我們項目的開(kāi)發(fā)提供了范圍廣大的選擇余地。XDoclet可以使你在面向組件的開(kāi)發(fā)過(guò)程中運用XP所積極倡導的持續集成(Continuous Integration)開(kāi)發(fā)方式,并且在EJB組件的開(kāi)發(fā)中開(kāi)發(fā)者只需集中編輯唯一一個(gè)Java源代碼文件即可。這帶來(lái)的好處是不言而喻的:首先,每個(gè)組件只與一個(gè)文件打交道會(huì )使你比較清晰地了解組件的整個(gè)概貌,這在當組件包含多個(gè)文件的情況下好處是非常明顯的。如果你曾經(jīng)開(kāi)發(fā)過(guò)EJB組件你就會(huì )很容易理解了,通常單個(gè)EJB組件會(huì )包含7個(gè)以上的文件,這時(shí)借助XDoclet你僅僅需要維護一個(gè)文件,其余的文件讓代碼自動(dòng)生成。其次,使用XDoclet可以大幅簡(jiǎn)化J2EE應用的開(kāi)發(fā)工作,你可以編寫(xiě)enterprisebean的具體實(shí)現,讓XDoclet去生成諸如Interface,value objects(值對象),struts forms等等其它的代碼,而且XDoclet還遵循許多業(yè)界公認的J2EE模式。
結束語(yǔ)
得益于天才的懶惰“ 美德”,我們有幸擁有了XDoclet,憑借XDoclet我們可以顯著(zhù)縮減開(kāi)發(fā)時(shí)間,并集中精力于我們的業(yè)務(wù)邏輯,經(jīng)驗表明:XDoclet可以生成大約85%的代碼量。當我們坐享這豐盛的免費午餐時(shí),你是否已從這種天才的懶惰“美德”中品味出了創(chuàng )造或者是創(chuàng )新的勤奮呢? |
聯(lián)系客服