摘要
這篇文章介紹了通過ANT任務的擴展來實現IoC管理對象或非管理對象的執行。同時也介紹了OGNL(對象圖形導航語言)如何被用來使ANT執行任何方法表達式,包括帶有運行時參數的。也介紹了如何使用JUNIT來測試ANT的擴展。
此外,還包含一個使用SPRING框架的實現。Ant-IoC的組合為創建松耦合的軟件開發支持任務開創了新的天地。
我需要增加一個基于ANT驅動的新任務,并且我用SPRING(一個輕量級的IoC框架)來實現這個任務。我幾乎沒有碰到什么問題,因為IoC容器是非侵入式的,這很容易創建一個包裝或者直接使用對象來實現任務。于是我開始想知道是否ANT可以直接使用SPRING配置的對象,然后重用已經定義和測試的依賴圖和配置。那為什么還要重復和引入波紋效應或其他問題呢?如果IoC容器果真能提供這樣的便利,就可以保證更直接的使用。
這篇文章介紹了這種方法并且演示了一種概念上的實現。剛接觸ANT擴展的開發者會發現這個例子十分有趣。
ANT擴展
為了給ANT增加自定義任務,ANT手冊建議使用為這個目的而提供的類,如Task類。但是這個建議不是強制的,ANT可以執行任何擁有execute()方法的類(當然ANT也可以通過使用exec或java任務來執行任何程序,但那是另一種擴展方式)。ANT也支持集成這些任務擴展到各種類型的屬性或XML文件中。
給ANT增加一個自定義任務的最佳方法是通過Task擴展來重用IoC框架。因此,執行獨立應用的Task必須設置和使用建立在ANT基礎上的框架內置的對象和資源。
控制反轉
IoC設計模式,也稱作DI(依賴注射)。在框架的上下文中,這與JAVA對象的組成有關。在IoC框架上增加的投資很大一部分是由于SPRING框架的開發人員演示了在一個IoC/AOP/XML/JavaBeans輕量框架中的協同作用,而這正是通過允許為其他API或組件創建強大的抽象層來提供超越DI能力的原因。SPRING本身就是一個使用IoC的例子。ANT看起來與IoC容器相適應,因為他也是基于XML或者JavaBean的,從某方面來說,他也使用了IoC。
需求
我們的ANT IoC任務擴展需求可以通過角色/目標/需求的格式來定義(這里的需求不分順序):
●角色:開發人員
●目標:修改IoC任務
●需求:
在任何代碼改變或構建后執行回歸測試
很容易在回歸測試中增加新的測試用例
支持不同的IoC框架
通過修改ANT日志的級別或IoC日志的配置使調試時可以得到更有效的輸出
●角色:構建創建人
●目標:編輯ANT目標并使用任務來定義IoC容器的輸入或輸出Bean
●需求:
設置IoC描述符的位置
在不需要容器時,定義FQCN(完全限定類名)作為目標
使用IoC時,設置POJO(普通JAVA對象)Bean名,缺省為antBean
定義目標方法名,缺省為execute
定義一個調用可以帶參數的表達式的方法
定義可以插入目標Bean的屬性,用來復寫容器屬性
定義目標的元素文本
沒有必要定義用來處理Ant/IoC組合的新類
為了各種擴展需要重用現存的屬性文件
●角色:任務擴展對象
●目標:執行對象方法
●需求:
執行在IoC Bean定義中定義的POJO
執行容器外的定義類
如果沒有定義使用缺省的Bean名antBean
執行簡單的方法,缺省為execute()
執行帶可選參數的方法表達式
如果目標是ANT相關的則插入工程
插入動態屬性
任務
支持這些需求的任務定義是SpringContextTask
描述
這個任務執行由SPRING容器管理的或者是未管理的FQCN的對象的方法。目前還不支持SRPING Bean定義引用的Classpath。
SpringContextTask的參數如下表所示:
例子
最簡單的應用我們的ANT任務擴展的例子如下:
&!-- create the task definition -->&taskdef name="runBean" classpathref="testpath" classname="jbetancourt.ant.task.spring.SpringContextTask"/>&target name="simpleAppContextUseWithDefaults"> &runBean beanLocations="applicationContext.xml">&/runBean>&/target>
simpleAppContextUseWithDefaults目標執行在文件路徑中找到的Bean定義文件applicationContext.xml中的Bean名為antBean的execute()方法。路徑屬性名是復數的以便將來支持多個Bean定義文件。
Bean的執行類似ANT執行對象的方法;然而,這里是IoC容器來管理Bean。容器可以增加事務依賴,包裝數據庫,設置網絡服務代理,使用遠程甚至提供AOP代理來代替實際目標Bean。我們的方法簡化了配置,因為ANT腳本不再需要知道如何配置對象,特別是復雜的對象。但是如果ANT腳本確實需要為服務調用設置特定的屬性時會怎么樣呢:
&target name="publish"> &spring beanLocations="applicationContext.xml" beanName="siteGenerator" methodName="generateSite" host="${host.site.url}" port="${site.port}"> Made a few tweaks. Removed some sentence fragments. &/spring> &/target>
注意因為任務名已經在taskdef中定義了,使用的名字將依賴于ANT的taskdef定義。這兒任務名是spring,F在我們定義Bean名字和調用的方法。元素文本也會被放到目標Bena中。在這個例子中,文本是一個發布的注釋。
通過使用ANT的動態屬性功能,我們也可以將需要的屬性放到目標對象中。通常在ANT文件中一個屬性被解析時,對應的set方法會被調用。使用動態屬性,非對象屬性或字段會通過setDynamicAttribute()方法被增加到對象中。通常因為容器已經包裝了其中的Bean的屬性,這種屬性注入提供了一種重寫的能力。但是,是否這樣會將配置復雜化?我們將不得不維護ANT任務使用的屬性及管理對象所需要的屬性。
當然這不是必須的;如例子中的SPRING用法,相同的屬性文件被ANT和SPRING同時使用— 即使使用了ANT的占位符語法(${...})。SPRING提供了這種目的的類,如PropertyPlaceHolderConfigurer。因此,這種方法不會引入新的配置惡夢?蓞⒖寂宰ⅰ皩傩灾械膶傩浴鲍@得更多的幫助。
另一種放置屬性的方法是通過使用call屬性來調用帶運行時參數的目標方法或者嵌套的methodCall元素,他的內容是java表達式。這個元素很容易使用因為XML需要的符號如實體轉義符可以用CDATA來避免:
call="generateSite("${host.site.url}","${site.port}")" Or better: &methodCall>&![CDATA[ generateSite("${host.site.url}","${site.port}") ]]>&/methodCall>
因此先前的例子可以如下寫法:
&target name="publish"> &spring beanLocations="applicationContext.xml" beanName="siteGenerator"> &methodCall> generateSite("${host.site.url}","${site.port}") &/methodCall> Made a few tweaks. Removed some sentence fragments. &/spring> &/target>
當然,目標對象必須包含需要的方法和參數標識符。
上面的例子簡單介紹了SpringContextTask方法?赡芩麄兛梢杂衅渌蚋玫膶崿F。
有人可能會對這個Task擴展的特性有疑問,如調用任何方法的功能。這個功能甚至可以被移除,因為任何不包含execute()方法的目標Bean可以被包裝,一個任務在IoC框架中可能更容易完成。但既然通過OGNL(后面會討論)支持方法表達式很容易,那么方法參數的支持也不是個問題了。
有趣的是,既然任何方法可以被調用,那么同一對象可以在同一個構建文件中被重用來提供不同的服務,這樣就可以在執行需要很多屬性的任務中減少過度的ANT腳本混亂了。如果任務實例可以通過ID來引用的話這個功能就會有實際意義了。我們可以象下面這樣寫:
&spring id="metrics" beanLocations="metricsContext.xml" beanName="main" exampleAttribute="a value" and so forth . . ./> &target name="ComputeMetrics"> &spring refid="metrics" call="computeNCSS"/> &spring refid="metrics" call="computeCCM"/> &spring refid="metrics" call="findBugs"/> &/target> &target name="genDocs"> &!- here are calls to other types of docs '/> &!- now call the metric docs '/> &spring refid="metrics" call="createDocs"/> &/target>
現在我們擁有更易讀的格式而隱藏了更多的信息。我們不再關心容器中有什么,只要那兒有一個入口點—main.那個Bean可以是實際的Bean或者通過依賴注射代理給其他工具如PMD, JavaNCSS, 或者FindBugs。
我沒有選擇通過ID引用重用SpringContextTask的開發方式。另一種完成重用的方式是在上下文中使用不同的Bean,如:
&target name="ComputeMetrics"> &spring beanLocations="metricsContext.xml" beanName="computeNCSS"/> &spring beanLocations="metricsContext.xml" beanName="computeCCM"/> &spring beanLocations="metricsContext.xml" beanName="findBugs"/>&/target>
但在這個例子中的每一個Bean必須有一個execute()方法來啟動服務。而且每一個Bean實際上只是引用同樣的類或對象。
現在需求已經確定而
文章來源于領測軟件測試網 http://www.kjueaiud.com/
版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
技術支持和業務聯系:info@testage.com.cn 電話:010-51297073
老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月