程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> AOP在大規模軟件開發項目中應用的嘗試與思考

AOP在大規模軟件開發項目中應用的嘗試與思考

編輯:JAVA編程入門知識
  本文的寫作源於一個真實的大型軟件開發項目,我們努力嘗試在這個項目中推廣應用AOP。在此我們將對曾經面臨過的一些實際問題與困難進行分析,試圖引發關於面向方面軟件開發(AOSD)的一些更深層次的思考。 <!-- frame contents --> <!-- /frame contents --> 本文的作者將站在開發者的角度做出客觀的判定,既不是AOP的狂熱鼓吹者,同樣也不是AOP反對陣營的一員。因此可以視作來自Java開發者對AOP技術應用的客觀分析和建設性意見。
  
  關於AOP
  
  關於AOP的概念,筆者在這裡不再贅述。誰最先創造了AOP,業界一直有些爭議,但普遍接受的說法大概是最先由Gregor J Kiczales在ECOOP'97提出來的,隨後Gregor又申請了AOP的專利[US06467086]。很多人可能不太服氣,因為他們或多或少早已有了類似的想法,只不過沒有想到給他起個新名字罷了。無論是OOP,MOP,還是AOP,其本質的想法都是試圖在更貼近現實世界的層次上實現軟件開發的模塊化。從這個角度看,AOP的想法不過是新瓶裝舊酒罷了。其實AOP作為新生事物的出現,並不是一種技術上的飛躍,而是軟件模塊化發展到某一個階段的一個階段性產物。人的思維通常都有一些慣性,在我們飽嘗了OOP的艱辛後,有一種新的概念跳出來分析總結了OOP的某些缺點,而且以看起來合理的方式做出改進,難免會給大家一種耳目一新的感覺。但不可否認的是,到目前為止,AOP角色所扮演的應用角色更多的只是對OOP的一種補充,因此作為一種重要的"OP"存在似乎有些名過其實,看起來更像是一種高級的設計模式。然而,在很多人的眼中AOP的分量甚至不亞於OOP,甚至AOP被視作未來軟件開發的一個趨勢。筆者一直思考一個問題,AOP出現的七八年時間在IT界並不算很短了,有趣的現象是AOP始終保持了小火慢炖的熱度,一直沒有像大家所期望的那樣大紅大紫起來。
  
  那麼AOP究竟在多大程度上可以幫助我們解決實際的問題呢?讓我們嘗試在一個真實的軟件開發項目中應用AOP。對AOP所推崇的各個典型應用方向加以研究,例如,日志(Log),事務(Transaction), 安全性(Security), 線程池等等。必須說明,我們這裡提到的場景,是有一定規模的軟件產品開發,我們最終完成的是百兆數量級的軟件產品,因此我們研究的范圍既不是程序員的個人行為,也不是小范圍的示例。讓我們一起來看一看有什麼有趣的發現。
  
    AOP的實踐
  

  我們試驗應用AOP的方向很多,這裡僅以最具代表性的Log為例。大多數人了解AOP,都是從經典的Log 關注點的剝離開始的。因此這是每一個AOP的愛好者都耳熟能詳的案例。按道理,應該是無可爭辯的。很不幸,在我們的研究過程中還是碰到了很棘手的問題。
  
  讓我們來看一看一個經典的AOP 做日志的例子。
  
  我們假定,按照AOP的思想,主邏輯的開發人員在寫代碼的時候不應該考慮邊緣邏輯。因此,上述的日志代碼實際對主邏輯的開發者不可見。假定我們以主流的Log4J為記日志的實現方式,以ASPectJ作為Aspect的實現方式。需要重申,本文的寫作目的並不是針對某一種AOP的實現平台,選用AspectJ主要因為從語法的角度而言,AspectJ是目前所有AOP實現中覆蓋范圍最廣的一種實現。
  
  這樣一個記日志的橫切關注點描述,是最經典的AOP應用,它本身是沒有任何問題的。通常我們會怎樣用它呢?在繼續了這個抽象Aspect的子Aspect實現中指定切入點的位置①,並在這個位置上將實現的邏輯填入通知(Advice)②。
  
  在一個小規模的應用開發環境中這樣做是不會有問題的,首先,記日志的切入點不多,無論是采用一對一的位置直接描述,還是利用統一的編碼規范來約束都是可行的方案;其次,通知中的邏輯不會很復雜。整體的軟件開發流程不會有什麼變化的需要,通常的做法是由專門的Aspect開發人員統一編寫Aspect,而由大家共享記Log的Aspect。但是不鼓勵每一個開發人員都寫自己的Aspect,這樣就不是橫(cross-cut),變成過篩子了(cross-point),軟件開發變成一盤散沙,失去控制,AOP帶來的好處喪失殆盡。
  
  那麼,在我們的項目中,情況怎樣呢?上述看似簡單的兩個點都存在問題:
  
  (1) 具我們統計,在我們開發的軟件上一個版本的軟件代碼中,總共有7萬句記Log的調用。假如我們不做任何相關的總結工作,直接一對一的對切入點進行描述,那麼在位置①上的切入點描述就有7萬條之多;姑且不算工作量,即使這樣做了,將來帶來的代碼維護將是天文數字的成本,此路不通。
  
  那麼我們只能寄希望能夠提煉出這7萬句日志調用的公共模式,我們在這裡用到的是一種優化過的Log組件,接口與LOG4J類似,考慮到LOG4J的廣泛應用,我們下面將以LOG4J為參照。Log Level類中預定義了五個級別,DEBUG, INFO, WARN, ERROR,FATAL,根據統計,Fatal類型的調用最少,根據Fatal的級別定義,我們或許可以花一定時間整理代碼,提煉出捕捉Fatal點的規則。然後次之,WARN和ERROR大約占7%左右,這一部分就不好辦了,WARN/ERROR類型的LOG並沒有嚴格的界定,代碼的分布點也難尋規律,一定要找到規律,要付出相當大的代價。最後,DEBUG, INFO占據了很大的比例30%-50%,顧名思義,這一部分的代碼出現的隨機性很大,無論怎樣努力都不可能找到有意義的公共規律。此路還是不通。
  
  有一種說法也許可以解釋這種想象:假如切入點難於描述的時候,很大原因是因為關注點的定義不准確。此說法有一定道理,以"日志"作為一個方面來切入粒度似乎太大了。那麼,唯一的辦法是將"日志"關注點進一步拆解。一直拆解到可以接受的程度。但是,我們的問題似乎還沒有解決,假如我們的項目足夠小,那麼這樣的拆解總是有一定的限度的,這種做法或許可行。但很不幸,我們的項目很大,要經過相當多的分解才能最終找到日志的規律性。我們還是可能需要成百上千條語句來指定切入點的位置,最終的結果將很難維護,這樣的做法對於一個不斷演化中的項目而言是脆弱乃至於不可接受的。況且,像Debug這樣的Log級別,無論你怎樣拆解,都不可能找到完美的規律。通常,任何一個系統中的Log都會保持邏輯的一致性,假如經過了這樣的層層分解,Log作為一個邏輯主體的完整性被完全破壞了。這是一種為了AOP而AOP的做法,非但工作量沒有減輕,還帶來了無窮的後患。
  
  好了,只剩最後一招了,為了用AOP, 我們犧牲掉Log的某些特性,預先定義好編碼的規則和日志原則,強制推行。當然,假如想要全面覆蓋所有的日志點,這樣的日志原則只能定得非常粗。從AOP的角度來講,技術上是可行的,但粗放的日志規則會帶來Log的信息量瘋長,對於我們的軟件項目來說,還是不可接受,因為日志失去了它的精確性,會對系統的維護產生較大影響,而且大量日志信息的增長對系統整體運行性能的沖擊是顯而易見的。
  
  (2) 在圖1 的第二個要點上我們也同樣面臨問題,也許從圖上的例子你可能還看不出來,因為在所有的介紹AOP的文檔材料中介紹Log的例子都很簡單。但是現實生活中的Log很不留情面。很多時候程序對Log的調用都有其非凡的原因,它們的Advice需要分別編寫。例如在例子產品中我們經常需要把一個變量傳給"日志"方面, 而且,經常要傳入一個局部變量。至少現在,所有的AOP實現都還不支持對局部變量的捕捉,在可見的將來也不會有這種實現。好吧,只好重構代碼,假如您想傳參數,必須要遵守我們預先定義的編碼命名規則。但是,這樣給編程人員帶來的限制會很大,你很難說服開發人員手捧厚厚的編碼規范,小心翼翼的寫程序。
  
  綜合上述兩個致命缺陷,我們試圖推行Log Aspect的工作已經碰到了相當的阻力。進入討論組討論。
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved