熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

輕量級IoC容器來擴展ANT享受SPRING(圖)

2013-11-23 20:25:05  來源: Java開源技術 

  摘要
  
  這篇文章介紹了通過ANT任務的擴展來實現IoC管理對象或非管理對象的執行同時也介紹了OGNL(對象圖形導航語言)如何被用來使ANT執行任何方法表達式包括帶有運行時參數的也介紹了如何使用JUNIT來測試ANT的擴展此外還包含一個使用SPRING框架的實現AntIoC的組合為創建松耦合的軟件開發支持任務開創了新的天地
  
  我需要增加一個基於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 classpat   classname=jbetancourtanttaskspringSpringContextTask/>&target name=simpleAppContextUseWithDefaults>  &runBean beanLocations=applicationContextxml>&/runBean>&/target>
  
  simpleAppContextUseWithDefaults目標執行在文件路徑中找到的Bean定義文件applicationContextxml中的Bean名為antBean的execute()方法路徑屬性名是復數的以便將來支持多個Bean定義文件
  
  Bean的執行類似ANT執行對象的方法然而這裡是IoC容器來管理Bean容器可以增加事務依賴包裝數據庫設置網絡服務代理使用遠程甚至提供AOP代理來代替實際目標Bean我們的方法簡化了配置因為ANT腳本不再需要知道如何配置對象特別是復雜的對象但是如果ANT腳本確實需要為服務調用設置特定的屬性時會怎麼樣呢
  
  &target name=publish>   &spring     beanLocations=applicationContextxml     beanName=siteGenerator      methodName=generateSite     host=${hostsiteurl}     port=${siteport}>     Made a few tweaks Removed some sentence fragments     &/spring>            &/target>
  
  注意因為任務名已經在taskdef中定義了使用的名字將依賴於ANT的taskdef定義這兒任務名是spring現在我們定義Bean名字和調用的方法元素文本也會被放到目標Bena中在這個例子中文本是一個發布的注釋
  
  通過使用ANT的動態屬性功能我們也可以將需要的屬性放到目標對象中通常在ANT文件中一個屬性被解析時對應的set方法會被調用使用動態屬性非對象屬性或字段會通過setDynamicAttribute()方法被增加到對象中通常因為容器已經包裝了其中的Bean的屬性這種屬性注入提供了一種重寫的能力但是是否這樣會將配置復雜化?我們將不得不維護ANT任務使用的屬性及管理對象所需要的屬性
  
  當然這不是必須的如例子中的SPRING用法相同的屬性文件被ANT和SPRING同時使用— 即使使用了ANT的占位符語法(${})SPRING提供了這種目的的類如PropertyPlaceHolderConfigurer因此這種方法不會引入新的配置惡夢可參考旁注屬性中的屬性獲得更多的幫助
  
  另一種放置屬性的方法是通過使用call屬性來調用帶運行時參數的目標方法或者嵌套的methodCall元素他的內容是java表達式這個元素很容易使用因為XML需要的符號如實體轉義符可以用CDATA來避免
  
  call=generateSite("${hostsiteurl}""${siteport}") Or better: &methodCall>&![CDATA[  generateSite(${hostsiteurl}${siteport})  ]]>&/methodCall>
  
  因此先前的例子可以如下寫法
  
  &target name=publish>   &spring beanLocations=applicationContextxml beanName=siteGenerator>     &methodCall> generateSite(${hostsiteurl}${siteport}) &/methodCall>     Made a few tweaks Removed some sentence fragments     &/spring>            &/target>
  
  當然目標對象必須包含需要的方法和參數標識符
  
  上面的例子簡單介紹了SpringContextTask方法可能他們可以有其他或更好的實現
  
  有人可能會對這個Task擴展的特性有疑問如調用任何方法的功能這個功能甚至可以被移除因為任何不包含execute()方法的目標Bean可以被包裝一個任務在IoC框架中可能更容易完成但既然通過OGNL(後面會討論)支持方法表達式很容易那麼方法參數的支持也不是個問題了
  
  有趣的是既然任何方法可以被調用那麼同一對象可以在同一個構建文件中被重用來提供不同的服務這樣就可以在執行需要很多屬性的任務中減少過度的ANT腳本混亂了如果任務實例可以通過ID來引用的話這個功能就會有實際意義了我們可以象下面這樣寫
  
  &spring id=metrics beanLocations=metricsContextxml 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=metricsContextxml beanName=computeNCSS/>  &spring beanLocations=metricsContextxml beanName=computeCCM/>  &spring beanLocations=metricsContextxml beanName=findBugs/>&/target>
  
  但在這個例子中的每一個Bean必須有一個execute()方法來啟動服務而且每一個Bean實際上只是引用同樣的類或對象
  
  現在需求已經確定而
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28461.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.