卞世暉,李龍澍,陳圣兵,李 浩
(1.安徽大學 計算機學院,安徽 合肥 230039;2.武漢理工大學 計算機學院,湖北 武漢430070)
面向對象編程OOP(Object-Oriented Programming)的開發方法是把軟件系統看成各種對象的集合,采用抽象、封裝、繼承和多態的方法維護系統功能。但隨著OOP技術應用實踐的增多和應用范圍的擴大,逐漸暴露出其不足和局限性。比如一個系統中有幾十個或幾百個數據庫查詢函數,每個地方都要求記錄數據庫查詢的語句,OOP技術只能為每個函數增加記錄日志,卻沒有更好的辦法。而面向方面編程AOP(Aspect-Oriented Programming)技術則通過方法攔截解決,在每個方法調用前后或出現異常時記錄日志信息[1]。
AOP是通過分離核心關注點和橫切關注點,削弱二者之間的耦合度。利用AOP技術可對相關的橫切關注點進行封裝,從而保證橫切關注點的復用,并根據需要適時增添、撤除、改變橫切性關注點,而不影響核心關注點,提高系統的擴展性和靈活性。文中Struts2中的攔截器采用AOP的設計理念,通過定義、配置攔截器,攔截器可以按照“插拔”方式攔截相應的請求,配合業務控制器處理該請求。
攔截器采用AOP的設計理念,攔截是AOP的一種實現策略。AOP是針對OOP的局限性所提出的一種新的編程思想,是對OOP的補充和完善,它可以有效提高代碼復用性,提高開發效率[2]。OOP技術引入封裝、繼承和多態性等概念建立一種對象層次結構,用以模擬公共行為的一個集合。但OOP不能為分散的對象引入公共行為。也就是OOP允許定義從上到下的關系,但并不適合定義從左到右的關系。例如安全驗證、日志等功能往往水平散布在所有對象層次中,而與其所散布到的對象核心功能沒有關系。這些散布在各處的代碼被稱為橫切代碼,在OOP設計中,它們造成大量代碼的重復,不利于各個模塊的復用。而AOP則可以減少系統中的重復代碼,有效降低各模塊間的耦合度,方便以后的維護和操作,它采用一種稱為“橫切”的技術,剖解開封裝的對象內部,將影響多個類的公共行為封裝到一個可重用模塊,并將其稱為“方面”。AOP代表一種橫向的關系,在AOP中,將具有公共邏輯的、與其他模塊的核心模塊糾纏在一起的行為稱為“橫切關注點”,AOP就是要封裝這些橫切性關注點,以實現代碼的復用性、靈活性和擴展性。
攔截器是可在某個方法或字段訪問之前進行攔截,然后在之前或之后加入某些操作的一種程序設計思想[3]。AOP通過攔截實現關注點織入,一般要攔截一個方法可采用回調方法或動態代理。由于動態代理比較靈活,所以大多數AOP都采用動態代理實現,代理對象提供一種代理方式控制原對象的訪問[4]。JDK開發包提供動態代理支持,開發者可通過實現java.lang.reflect.InvocationHandler接口提供一個執行代理器,然后通過java.lang.reflect.Proxy得到一個代理對象,通過該代理對象執行被代理類(業務邏輯)方法,在被代理類(業務邏輯)方法被調用的同時,執行處理器會被自動調用。
Struts2中的攔截器如圖1所示。Struts2的Action被一個或多個攔截器所包圍,所有用戶請求都會被攔截器所攔截,然后交給Action處理。該調用流程由配置文件實現,當用戶請求到達Struts2的 ServletDispacher時 ,Struts2會查找配置文件,并根據其配置實例化相對應的攔截器對象,然后串成一個列表(list),最后逐個調用列表中的攔截器。

圖1 Struts2攔截器
通過攔截形成攔截器模塊,大大提高系統開發的靈活性和復用性,AOP使用代理方式,將多個攔截器和核心業務邏輯組合在一起,滿足用戶業務需求,這種機制克服了傳統OOP設計思想所帶來的各種弊端,結合OOP設計,為項目開發提供較完善的解決思路。
很多公共操作并不是所有Action都要實現的,而攔截器能將這些公共操作進行動態組合,以“插拔”方式應用到Action中[5]。開發者可根據業務需要,分離出日志記錄、安全認證、文件上傳、國際化等多個攔截器。攔截器的特點就是可插拔性[6],如圖 2所示,攔截器1和攔截器2都是可“插拔”的,用戶可以根據自己需要,增加或減少攔截器,或調整攔截器的順序。當需要某個攔截器時,只需“插入,不需要時“拔出”即可。

圖2 攔截器的插拔性
攔截器的“插拔“實際是通過Struts2框架的配置文件實現的,配置文件中可定義攔截器和攔截器棧,并可在Action中定義所使用的攔截器或攔截器棧(攔截器棧就是由多個攔截器組成的一個攔截器組)。在struts.xml配置文件中,攔截器的定義使用
定義好攔截器或攔截器棧后,可在配置文件中使用該攔截器或攔截器棧來攔截Action,指定的攔截器或攔截器棧會在Action的execute()方法執行前被執行。在配置文件的Action配置中,使用
攔截器可應用于用戶的權限認證、系統的日志記錄等方面,這里以一個銀行業務的日志記錄為例說明攔截器的應用。銀行的每一個業務操作(如轉賬、存款、匯款等),基本都要進行日志記錄。在傳統設計中,要在每一個業務操作前后進行相同記錄(如經辦人、交易時間、交易金額一類),不僅造成代碼的臃腫,而且使得這些日志記錄與業務操作耦合在一起,不利于系統的維護和升級,靈活性也較差。而采用AOP的設計思想,則可把業務操作的日志記錄作為一個“橫切關注點”分離出來,分離出來的日志記錄模塊在Struts2中應用攔截器實現,并不會影響業務模塊的實現。需要時只要把該攔截器“插入”到Aicton中即可。首先建立一個日志記錄攔截器,其關鍵代碼如下:

定義好攔截器后,就可以在配置文件中使用。為了使用日志記錄攔截器,需要建立一個Action。由于設置了攔截器,所以可在Action前后自動執行,很方便地在需要時加入該攔截器,而且這種方式是動態的,并且功能自由組合。
攔截器采用一種橫切式、可插拔的設計思想,提高了代碼的靈活性。攔截器更為靈活的使用方法,如攔截器的方法過濾、攔截器的執行順序、設置攔截器參數等,進一步增強了攔截器的靈活性。攔截器是實現代碼復用性、擴展性的有效方法,因此會得到更廣泛應用。
[1]Walls C,Breidenbach R.Spring in action[M].Beijing:Manning Publications,2007.
[2]張英捷,劉萬軍.Spring AOP技術在J2EE系統安全性驗證中的應用研究[J].計算機科學與工程,2008,30(8):137-138.
[3]王濤濤,李曉禹,施煒利.Struts2攔截器控制頁面訪問權限的設計與實現[J].計算機與現代化,2009(1):32-33.
[4]曹曉利,郭順生.AOP技術及其在J2EE中的動態代理實現[J].計算機技術與發展,2008,18(11):121-122.
[5]崔群法,王詠梅,李有軍.Struts2.0從入門到精通[M].北京:電子工業出版社,2009.
[6]閆術卓,楊 強.Struts2技術詳解[M].北京:電子工業出版社,2008.