明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

AOP在大規(guī)模軟件開發(fā)項目中應(yīng)用的嘗試與思考

[摘要]本文的寫作源于一個真實的大型軟件開發(fā)項目,我們努力嘗試在這個項目中推廣應(yīng)用AOP。在此我們將對曾經(jīng)面臨過的一些實際問題與困難進行分析,試圖引發(fā)關(guān)于面向方面軟件開發(fā)(AOSD)的一些更深層次的思考。本文的作者將站在開發(fā)者的角度做出客觀的判斷,既不是AOP的狂熱鼓吹者,同樣也不是AOP反對陣營的一員。...
本文的寫作源于一個真實的大型軟件開發(fā)項目,我們努力嘗試在這個項目中推廣應(yīng)用AOP。在此我們將對曾經(jīng)面臨過的一些實際問題與困難進行分析,試圖引發(fā)關(guān)于面向方面軟件開發(fā)(AOSD)的一些更深層次的思考。本文的作者將站在開發(fā)者的角度做出客觀的判斷,既不是AOP的狂熱鼓吹者,同樣也不是AOP反對陣營的一員。因此可以視作來自Java開發(fā)者對AOP技術(shù)應(yīng)用的客觀分析和建設(shè)性意見。

  關(guān)于AOP

  關(guān)于AOP的概念,筆者在這里不再贅述。誰最先創(chuàng)造了AOP,業(yè)界一直有些爭議,但普遍接受的說法大概是最先由Gregor J Kiczales在ECOOP'97提出來的,隨后Gregor又申請了AOP的專利[US06467086]。很多人可能不太服氣,因為他們或多或少早已有了類似的想法,只不過沒有想到給他起個新名字罷了。無論是OOP,MOP,還是AOP,其本質(zhì)的想法都是試圖在更貼近現(xiàn)實世界的層次上實現(xiàn)軟件開發(fā)的模塊化。從這個角度看,AOP的想法不過是新瓶裝舊酒罷了。其實AOP作為新生事物的出現(xiàn),并不是一種技術(shù)上的飛躍,而是軟件模塊化發(fā)展到某一個階段的一個階段性產(chǎn)物。人的思維通常都有一些慣性,在我們飽嘗了OOP的艱辛后,有一種新的概念跳出來分析總結(jié)了OOP的某些缺點,而且以看起來合理的方式做出改進,難免會給大家一種耳目一新的感覺。但不可否認(rèn)的是,到目前為止,AOP角色所扮演的應(yīng)用角色更多的只是對OOP的一種補充,因此作為一種重要的"OP"存在似乎有些名過其實,看起來更像是一種高級的設(shè)計模式。然而,在很多人的眼中AOP的分量甚至不亞于OOP,甚至AOP被視作未來軟件開發(fā)的一個趨勢。筆者一直思考一個問題,AOP出現(xiàn)的七八年時間在IT界并不算很短了,有趣的現(xiàn)象是AOP始終保持了小火慢燉的熱度,一直沒有像大家所期望的那樣大紅大紫起來。

  那么AOP究竟在多大程度上可以幫助我們解決實際的問題呢?讓我們嘗試在一個真實的軟件開發(fā)項目中應(yīng)用AOP。對AOP所推崇的各個典型應(yīng)用方向加以研究,例如,日志(Log),事務(wù)(Transaction), 安全性(Security), 線程池等等。必須說明,我們這里提到的場景,是有一定規(guī)模的軟件產(chǎn)品開發(fā),我們最終完成的是百兆數(shù)量級的軟件產(chǎn)品,因此我們研究的范圍既不是程序員的個人行為,也不是小范圍的示例。讓我們一起來看一看有什么有趣的發(fā)現(xiàn)。

  AOP的實踐

  我們試驗應(yīng)用AOP的方向很多,這里僅以最具代表性的Log為例。大多數(shù)人了解AOP,都是從經(jīng)典的Log 關(guān)注點的剝離開始的。因此這是每一個AOP的愛好者都耳熟能詳?shù)陌咐。按道理,?yīng)該是無可爭辯的。很不幸,在我們的研究過程中還是碰到了很棘手的問題。

  讓我們來看一看一個經(jīng)典的AOP 做日志的例子。

  我們假定,按照AOP的思想,主邏輯的開發(fā)人員在寫代碼的時候不應(yīng)該考慮邊緣邏輯。因此,上述的日志代碼實際對主邏輯的開發(fā)者不可見。假定我們以主流的Log4J為記日志的實現(xiàn)方式,以AspectJ作為Aspect的實現(xiàn)方式。需要重申,本文的寫作目的并不是針對某一種AOP的實現(xiàn)平臺,選用AspectJ主要因為從語法的角度而言,AspectJ是目前所有AOP實現(xiàn)中覆蓋范圍最廣的一種實現(xiàn)。

  這樣一個記日志的橫切關(guān)注點描述,是最經(jīng)典的AOP應(yīng)用,它本身是沒有任何問題的。通常我們會怎樣用它呢?在繼承了這個抽象Aspect的子Aspect實現(xiàn)中指定切入點的位置①,并在這個位置上將實現(xiàn)的邏輯填入通知(Advice)②。

  在一個小規(guī)模的應(yīng)用開發(fā)環(huán)境中這樣做是不會有問題的,首先,記日志的切入點不多,無論是采用一對一的位置直接描述,還是利用統(tǒng)一的編碼規(guī)范來約束都是可行的方案;其次,通知中的邏輯不會很復(fù)雜。整體的軟件開發(fā)流程不會有什么變化的需要,通常的做法是由專門的Aspect開發(fā)人員統(tǒng)一編寫Aspect,而由大家共享記Log的Aspect。但是不鼓勵每一個開發(fā)人員都寫自己的Aspect,這樣就不是橫(cross-cut),變成過篩子了(cross-point),軟件開發(fā)變成一盤散沙,失去控制,AOP帶來的好處喪失殆盡。

  那么,在我們的項目中,情況怎樣呢?上述看似簡單的兩個點都存在問題:

  (1) 具我們統(tǒng)計,在我們開發(fā)的軟件上一個版本的軟件代碼中,總共有7萬句記Log的調(diào)用。如果我們不做任何相關(guān)的總結(jié)工作,直接一對一的對切入點進行描述,那么在位置①上的切入點描述就有7萬條之多;姑且不算工作量,即使這樣做了,將來帶來的代碼維護將是天文數(shù)字的成本,此路不通。

  那么我們只能寄希望能夠提煉出這7萬句日志調(diào)用的公共模式,我們在這里用到的是一種優(yōu)化過的Log組件,接口與LOG4J類似,考慮到LOG4J的廣泛應(yīng)用,我們下面將以LOG4J為參照。Log Level類中預(yù)定義了五個級別,DEBUG, INFO, WARN, ERROR,F(xiàn)ATAL,根據(jù)統(tǒng)計,F(xiàn)atal類型的調(diào)用最少,根據(jù)Fatal的級別定義,我們或許可以花一定時間整理代碼,提煉出捕捉Fatal點的規(guī)則。然后次之,WARN和ERROR大約占7%左右,這一部分就不好辦了,WARN/ERROR類型的LOG并沒有嚴(yán)格的界定,代碼的分布點也難尋規(guī)律,一定要找到規(guī)律,要付出相當(dāng)大的代價。最后,DEBUG, INFO占據(jù)了很大的比例30%-50%,顧名思義,這一部分的代碼出現(xiàn)的隨機性很大,無論怎樣努力都不可能找到有意義的公共規(guī)律。此路還是不通。

  有一種說法也許可以解釋這種想象:如果切入點難于描述的時候,很大原因是因為關(guān)注點的定義不準(zhǔn)確。此說法有一定道理,以"日志"作為一個方面來切入粒度似乎太大了。那么,唯一的辦法是將"日志"關(guān)注點進一步拆解。一直拆解到可以接受的程度。但是,我們的問題似乎還沒有解決,如果我們的項目足夠小,那么這樣的拆解總是有一定的限度的,這種做法或許可行。但很不幸,我們的項目很大,要經(jīng)過相當(dāng)多的分解才能最終找到日志的規(guī)律性。我們還是可能需要成百上千條語句來指定切入點的位置,最終的結(jié)果將很難維護,這樣的做法對于一個不斷演化中的項目而言是脆弱乃至于不可接受的。況且,像Debug這樣的Log級別,無論你怎樣拆解,都不可能找到完美的規(guī)律。通常,任何一個系統(tǒng)中的Log都會保持邏輯的一致性,如果經(jīng)過了這樣的層層分解,Log作為一個邏輯主體的完整性被完全破壞了。這是一種為了AOP而AOP的做法,非但工作量沒有減輕,還帶來了無窮的后患。

  好了,只剩最后一招了,為了用AOP, 我們犧牲掉Log的某些特性,預(yù)先定義好編碼的規(guī)則和日志原則,強制推行。當(dāng)然,如果想要全面覆蓋所有的日志點,這樣的日志原則只能定得非常粗。從AOP的角度來講,技術(shù)上是可行的,但粗放的日志規(guī)則會帶來Log的信息量瘋長,對于我們的軟件項目來說,還是不可接受,因為日志失去了它的精確性,會對系統(tǒng)的維護產(chǎn)生較大影響,而且大量日志信息的增長對系統(tǒng)整體運行性能的沖擊是顯而易見的。

  (2) 在圖1 的第二個要點上我們也同樣面臨問題,也許從圖上的例子你可能還看不出來,因為在所有的介紹AOP的文檔材料中介紹Log的例子都很簡單。但是現(xiàn)實生活中的Log很不留情面。很多時候程序?qū)og的調(diào)用都有其特殊的原因,它們的Advice需要分別編寫。例如在例子產(chǎn)品中我們經(jīng)常需要把一個變量傳給"日志"方面, 而且,經(jīng)常要傳入一個局部變量。至少現(xiàn)在,所有的AOP實現(xiàn)都還不支持對局部變量的捕捉,在可見的將來也不會有這種實現(xiàn)。好吧,只好重構(gòu)代碼,如果您想傳參數(shù),必須要遵守我們預(yù)先定義的編碼命名規(guī)則。但是,這樣給編程人員帶來的限制會很大,你很難說服開發(fā)人員手捧厚厚的編碼規(guī)范,小心翼翼的寫程序。

  綜合上述兩個致命缺陷,我們試圖推行Log Aspect的工作已經(jīng)遇到了相當(dāng)?shù)淖枇Α?