劉海青
(多倫科技股份有限公司,江蘇 南京 211100)
AOP(Aspect-OrientedProgramming,面向方面編程)[1],所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便于減少系統的重復代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護性。AOP代表的是一個橫向的關系。使用“橫切”技術,AOP把軟件系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關系不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處都基本相似。比如權限認證、日志、事務處理。AOP的作用在于分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。其核心思想就是“將應用程序中的商業邏輯同對其提供支持的通用服務進行分離?!?/p>
面向對象編程主要用于為同一對象層次的公用行為建模。它的弱點是將公共行為應用于多個無關對象模型之間。而這恰恰是面向切面編程適合的地方。有了 AOP,我們可以定義交叉的關系,并將這些關系應用于跨模塊的、彼此不同的對象模型。AOP同時還可以讓我們層次化功能性而不是嵌入功能性,從而使得代碼有更好的可讀性和易于維護。
程序員需要參與三個部分:
1、定義普通業務組件,即核心業務組件;
2、定義切入點,一個切入點可能橫切多個業務組件;
3、定義增強處理,增強處理就是在AOP框架為普通業務組件織入的處理動作,即橫切業務組件。
目前AOP 多用代理的方式實現。以Spring[2]-[5]為例,框架在核心業務組件對象外封裝一個代理對象,并且在調用方法外封裝了一層調用方法,將橫切業務邏輯插入外部代理對象的調用方法中,以此實現AOP邏輯。這種實現方式顯得笨重而又繁瑣。
簡而言之,IoC容器需要在初始階段在業務組件外部動態創建一個Proxy,在Proxy對象中,根據配置文件定義的joinpoint找到相應的增強處理,做相應動作,可以通過如下簡要框圖和序列圖說明。
本文將提供一種對AOP實現方法的改進,通過對IoC容器的改進, 建立核心業務組件的通用接口,通過將橫切業務組件直接插入核心業務組件通用接口的方式,來實現輕量級的AOP框架。這種實現方式完全滿足AOP的業務需求,遠比代理方式實現簡單,并且更接近于AOP其原始概念,其中的關鍵是改進了IoC框架核心業務組件的調用方式,建立通用調用接口。
該方法只需在 IoC框架內實現 AOP管理器即可,無需對業務對象封裝代理對象,其主要組件為
1. AOP管理器;
2. 核心業務組件;
將框圖和序列圖做如圖2改進:

圖1 基于動態代理方式AOP實現的簡化框圖與序列圖Fig.1 Simplified block diagram and sequence diagram based on dynamic proxy approach

圖2 改進的輕量級AOP實現的簡化框圖與序列圖Fig.2 Simplified block diagram and sequence diagram for improved lightweight AOP implementation
首先,我們必須要為應用程序建立IoC框架,建立組件配置文件??蚣懿捎霉S模式創建組件,具體做法是讀取組件配置文件,通過反射的方式創建組件,并注冊到全局管理組件中。
在本文中,我們以C#代碼編寫的圖形編輯器為例,IoC框架由開發者自行編寫。
以下為配置文件的組件定義部分:
1. 將業務組件定義為Service,在配置文件中,name為組件名稱,class為實現類的類名。以下配置文件定義了一個業務組件,即文檔操作,實現新建、打開、保存、另存文檔的功能。

2. 將AOP的增強處理組件定義為Filter,以下配置文件定義了一個名為 DocumentLog,實現類為Src.Filter.DocumentLogFilter的增強處理組件,兩個trigger 代表了在兩種條件下觸發,一個在document業務組件Open事件后觸發,一個在document業務組件Save事件后觸發,該組件在文檔打開和保存后都會向操作日志中記錄用戶的操作信息,包括當前用戶名、操作時間、操作類型等。param屬性向增強處理組件傳入參數,以便其區分具體觸發情景。

3. 我們的IoC框架將根據配置文件創建service對象和filter,并注冊到管理組件ServiceManager和FilterManager中。目前為止介紹了IoC框架對組件的創建,下一章說明一項實現輕量級AOP框架所需的重要機制。
為了實現輕量級AOP框架,我們需要將普通業務組件稍加包裝,建立通用的方法調用接口。為此,引入了事件機制,即所有方法調用都描述成對象接收事件,統一都用一個方法調用,即事件監聽。
我們建立一個接口IService,有一個方法OnListener。建立一個抽象類Service用于實現這個接口,并通過eventName參數通過反射的方式映射到實際調用的方法。所有業務組件都繼承自這個抽象類。

自此通用業務組件機制建立完成,下面介紹如何使用這一機制。我們定義業務組件 DocumentService繼承自 Service,其命名空間為 Src.My-Service。


由于IoC框架為我們創建了該組件,并注冊到了ServiceManager中,這樣,我們只需這樣調用給業務組件:
ServiceManager.GetInstance().GetService(“docuemnt”).OnListener(“”, “Open”, null);
自此,該機制已經建立完成,下面將介紹如何便捷實現AOP。
由于業務組件有了統一的事件調用接口,我們只需在此接口部署 AOP關注點即可,我們把BeforeListen和AfterListen加入Service,并將event參數作為AOP管理組件FilterManager的輸入參數:


來判斷是否滿足過濾條件,如果滿足,則執行Src.Filter.DocumentLogFilter類中的 AOP增強處理邏輯。在此描述一下增強處理組件Filter的抽象類:

DocumentLogFilter便繼承自該類,其實現為:
namespace DFramework.FrameFoundation.FrameUI.FrameWidget


自此,我們便將AOP增強處理便捷的切入業務組件中。
由于有了統一的核心業務組件事件調用接口,我們可以在框架中直接將增強處理配置在組件調用接口中,便捷實現了的AOP切入功能,而無須再如Spring那樣創建一個繁重的 Proxy對象,并且這種實現方式更接近與AOP的本質。
[1] 鄭子儒. 面向方面編程的研究[J]. 科技創新與生產力,2008(4): 64-66
[2] 王福強. Spring揭秘[M]. 人民郵電出版社, 2009(9):122-245
[3] 陳雄華. 精通Spring 4.x: 企業應用開發實戰精通[M]. 中國公信出版集團, 2017(1)
[4] 沃爾斯(Craig Walls). Spring實戰(第3版)[M]. 人民郵電出版社2013(6)
[5] Spring 5官方文檔[S].
[6] Brett McLaughlin/Gary Pollice/David West. 深入淺出面向對象分析與設計[M]. 東南大學出版社2009(1)
[7] 李少輝. 面向對象與MVC 框架的融合[J]. 軟件, 2013,34(1): 82-84
[8] 葛管庫. MVC 模式下程序設計[J].軟件, 2013, 34(2): 49-51
[9] 李航. 基于通用試驗體系結構支撐平臺的組件框架設計模式[J]. 軟件, 2013, 34(5): 85-87
[10] 陳妍. 計算機軟件開發的規范化探析[J]. 軟件, 2313, 34(7):33-34
[11] 陸正, 周晨, 谷瑞. .NET 反射在Excel文件比較中的應用[J]. 軟件, 2013, 34(10): 27-29
[12] 楊柯. 分層技術在計算機軟件開發中的應用效果分析[J].軟件, 2013, 34(10): 47
[13] 陸青, 蔣志航. 計算機軟件應用體系結構模型研究[J]. 軟件, 2014, 35(1): 144-145
[14] 季文天, 郭清菊, 馬杰. 基于模型驅動的框架技術在數據采集平臺中的分析與應用[J]. 軟件, 2014, 35(3): 121-124
[15] 李娜. 淺談軟件工程技術發展[J]. 軟件, 2014, 35(3):204-205