劉海青
(多倫科技股份有限公司,江蘇 南京 211100)
AOP(Aspect-OrientedProgramming,面向方面編程)[1],所謂“方面”,簡單地說,就是將那些與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護(hù)性。AOP代表的是一個(gè)橫向的關(guān)系。使用“橫切”技術(shù),AOP把軟件系統(tǒng)分為兩個(gè)部分:核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)。業(yè)務(wù)處理的主要流程是核心關(guān)注點(diǎn),與之關(guān)系不大的部分是橫切關(guān)注點(diǎn)。橫切關(guān)注點(diǎn)的一個(gè)特點(diǎn)是,他們經(jīng)常發(fā)生在核心關(guān)注點(diǎn)的多處,而各處都基本相似。比如權(quán)限認(rèn)證、日志、事務(wù)處理。AOP的作用在于分離系統(tǒng)中的各種關(guān)注點(diǎn),將核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)分離開來。其核心思想就是“將應(yīng)用程序中的商業(yè)邏輯同對其提供支持的通用服務(wù)進(jìn)行分離?!?/p>
面向?qū)ο缶幊讨饕糜跒橥粚ο髮哟蔚墓眯袨榻!K娜觞c(diǎn)是將公共行為應(yīng)用于多個(gè)無關(guān)對象模型之間。而這恰恰是面向切面編程適合的地方。有了 AOP,我們可以定義交叉的關(guān)系,并將這些關(guān)系應(yīng)用于跨模塊的、彼此不同的對象模型。AOP同時(shí)還可以讓我們層次化功能性而不是嵌入功能性,從而使得代碼有更好的可讀性和易于維護(hù)。
程序員需要參與三個(gè)部分:
1、定義普通業(yè)務(wù)組件,即核心業(yè)務(wù)組件;
2、定義切入點(diǎn),一個(gè)切入點(diǎn)可能橫切多個(gè)業(yè)務(wù)組件;
3、定義增強(qiáng)處理,增強(qiáng)處理就是在AOP框架為普通業(yè)務(wù)組件織入的處理動(dòng)作,即橫切業(yè)務(wù)組件。
目前AOP 多用代理的方式實(shí)現(xiàn)。以Spring[2]-[5]為例,框架在核心業(yè)務(wù)組件對象外封裝一個(gè)代理對象,并且在調(diào)用方法外封裝了一層調(diào)用方法,將橫切業(yè)務(wù)邏輯插入外部代理對象的調(diào)用方法中,以此實(shí)現(xiàn)AOP邏輯。這種實(shí)現(xiàn)方式顯得笨重而又繁瑣。
簡而言之,IoC容器需要在初始階段在業(yè)務(wù)組件外部動(dòng)態(tài)創(chuàng)建一個(gè)Proxy,在Proxy對象中,根據(jù)配置文件定義的joinpoint找到相應(yīng)的增強(qiáng)處理,做相應(yīng)動(dòng)作,可以通過如下簡要框圖和序列圖說明。
本文將提供一種對AOP實(shí)現(xiàn)方法的改進(jìn),通過對IoC容器的改進(jìn), 建立核心業(yè)務(wù)組件的通用接口,通過將橫切業(yè)務(wù)組件直接插入核心業(yè)務(wù)組件通用接口的方式,來實(shí)現(xiàn)輕量級的AOP框架。這種實(shí)現(xiàn)方式完全滿足AOP的業(yè)務(wù)需求,遠(yuǎn)比代理方式實(shí)現(xiàn)簡單,并且更接近于AOP其原始概念,其中的關(guān)鍵是改進(jìn)了IoC框架核心業(yè)務(wù)組件的調(diào)用方式,建立通用調(diào)用接口。
該方法只需在 IoC框架內(nèi)實(shí)現(xiàn) AOP管理器即可,無需對業(yè)務(wù)對象封裝代理對象,其主要組件為
1. AOP管理器;
2. 核心業(yè)務(wù)組件;
將框圖和序列圖做如圖2改進(jìn):
圖1 基于動(dòng)態(tài)代理方式AOP實(shí)現(xiàn)的簡化框圖與序列圖Fig.1 Simplified block diagram and sequence diagram based on dynamic proxy approach
圖2 改進(jìn)的輕量級AOP實(shí)現(xiàn)的簡化框圖與序列圖Fig.2 Simplified block diagram and sequence diagram for improved lightweight AOP implementation
首先,我們必須要為應(yīng)用程序建立IoC框架,建立組件配置文件??蚣懿捎霉S模式創(chuàng)建組件,具體做法是讀取組件配置文件,通過反射的方式創(chuàng)建組件,并注冊到全局管理組件中。
在本文中,我們以C#代碼編寫的圖形編輯器為例,IoC框架由開發(fā)者自行編寫。
以下為配置文件的組件定義部分:
1. 將業(yè)務(wù)組件定義為Service,在配置文件中,name為組件名稱,class為實(shí)現(xiàn)類的類名。以下配置文件定義了一個(gè)業(yè)務(wù)組件,即文檔操作,實(shí)現(xiàn)新建、打開、保存、另存文檔的功能。
2. 將AOP的增強(qiáng)處理組件定義為Filter,以下配置文件定義了一個(gè)名為 DocumentLog,實(shí)現(xiàn)類為Src.Filter.DocumentLogFilter的增強(qiáng)處理組件,兩個(gè)trigger 代表了在兩種條件下觸發(fā),一個(gè)在document業(yè)務(wù)組件Open事件后觸發(fā),一個(gè)在document業(yè)務(wù)組件Save事件后觸發(fā),該組件在文檔打開和保存后都會(huì)向操作日志中記錄用戶的操作信息,包括當(dāng)前用戶名、操作時(shí)間、操作類型等。param屬性向增強(qiáng)處理組件傳入?yún)?shù),以便其區(qū)分具體觸發(fā)情景。
3. 我們的IoC框架將根據(jù)配置文件創(chuàng)建service對象和filter,并注冊到管理組件ServiceManager和FilterManager中。目前為止介紹了IoC框架對組件的創(chuàng)建,下一章說明一項(xiàng)實(shí)現(xiàn)輕量級AOP框架所需的重要機(jī)制。
為了實(shí)現(xiàn)輕量級AOP框架,我們需要將普通業(yè)務(wù)組件稍加包裝,建立通用的方法調(diào)用接口。為此,引入了事件機(jī)制,即所有方法調(diào)用都描述成對象接收事件,統(tǒng)一都用一個(gè)方法調(diào)用,即事件監(jiān)聽。
我們建立一個(gè)接口IService,有一個(gè)方法OnListener。建立一個(gè)抽象類Service用于實(shí)現(xiàn)這個(gè)接口,并通過eventName參數(shù)通過反射的方式映射到實(shí)際調(diào)用的方法。所有業(yè)務(wù)組件都繼承自這個(gè)抽象類。
自此通用業(yè)務(wù)組件機(jī)制建立完成,下面介紹如何使用這一機(jī)制。我們定義業(yè)務(wù)組件 DocumentService繼承自 Service,其命名空間為 Src.My-Service。
由于IoC框架為我們創(chuàng)建了該組件,并注冊到了ServiceManager中,這樣,我們只需這樣調(diào)用給業(yè)務(wù)組件:
ServiceManager.GetInstance().GetService(“docuemnt”).OnListener(“”, “Open”, null);
自此,該機(jī)制已經(jīng)建立完成,下面將介紹如何便捷實(shí)現(xiàn)AOP。
由于業(yè)務(wù)組件有了統(tǒng)一的事件調(diào)用接口,我們只需在此接口部署 AOP關(guān)注點(diǎn)即可,我們把BeforeListen和AfterListen加入Service,并將event參數(shù)作為AOP管理組件FilterManager的輸入?yún)?shù):
來判斷是否滿足過濾條件,如果滿足,則執(zhí)行Src.Filter.DocumentLogFilter類中的 AOP增強(qiáng)處理邏輯。在此描述一下增強(qiáng)處理組件Filter的抽象類:
DocumentLogFilter便繼承自該類,其實(shí)現(xiàn)為:
namespace DFramework.FrameFoundation.FrameUI.FrameWidget
自此,我們便將AOP增強(qiáng)處理便捷的切入業(yè)務(wù)組件中。
由于有了統(tǒng)一的核心業(yè)務(wù)組件事件調(diào)用接口,我們可以在框架中直接將增強(qiáng)處理配置在組件調(diào)用接口中,便捷實(shí)現(xiàn)了的AOP切入功能,而無須再如Spring那樣創(chuàng)建一個(gè)繁重的 Proxy對象,并且這種實(shí)現(xiàn)方式更接近與AOP的本質(zhì)。
[1] 鄭子儒. 面向方面編程的研究[J]. 科技創(chuàng)新與生產(chǎn)力,2008(4): 64-66
[2] 王福強(qiáng). Spring揭秘[M]. 人民郵電出版社, 2009(9):122-245
[3] 陳雄華. 精通Spring 4.x: 企業(yè)應(yīng)用開發(fā)實(shí)戰(zhàn)精通[M]. 中國公信出版集團(tuán), 2017(1)
[4] 沃爾斯(Craig Walls). Spring實(shí)戰(zhàn)(第3版)[M]. 人民郵電出版社2013(6)
[5] Spring 5官方文檔[S].
[6] Brett McLaughlin/Gary Pollice/David West. 深入淺出面向?qū)ο蠓治雠c設(shè)計(jì)[M]. 東南大學(xué)出版社2009(1)
[7] 李少輝. 面向?qū)ο笈cMVC 框架的融合[J]. 軟件, 2013,34(1): 82-84
[8] 葛管庫. MVC 模式下程序設(shè)計(jì)[J].軟件, 2013, 34(2): 49-51
[9] 李航. 基于通用試驗(yàn)體系結(jié)構(gòu)支撐平臺的組件框架設(shè)計(jì)模式[J]. 軟件, 2013, 34(5): 85-87
[10] 陳妍. 計(jì)算機(jī)軟件開發(fā)的規(guī)范化探析[J]. 軟件, 2313, 34(7):33-34
[11] 陸正, 周晨, 谷瑞. .NET 反射在Excel文件比較中的應(yīng)用[J]. 軟件, 2013, 34(10): 27-29
[12] 楊柯. 分層技術(shù)在計(jì)算機(jī)軟件開發(fā)中的應(yīng)用效果分析[J].軟件, 2013, 34(10): 47
[13] 陸青, 蔣志航. 計(jì)算機(jī)軟件應(yīng)用體系結(jié)構(gòu)模型研究[J]. 軟件, 2014, 35(1): 144-145
[14] 季文天, 郭清菊, 馬杰. 基于模型驅(qū)動(dòng)的框架技術(shù)在數(shù)據(jù)采集平臺中的分析與應(yīng)用[J]. 軟件, 2014, 35(3): 121-124
[15] 李娜. 淺談軟件工程技術(shù)發(fā)展[J]. 軟件, 2014, 35(3):204-205