AOP下的權(quán)限控制實(shí)現(xiàn) 摘要 面向方面的編程(AOP)是一種新的編程技術(shù),它彌補(bǔ)了面向?qū)ο蟮木幊?OOP)在跨越模塊行為上的不足。AOP引進(jìn)了Aspect,它將影響多個(gè)類(lèi)的行為封裝到一個(gè)可重用模塊中,它允許程序員對(duì)橫切關(guān)注點(diǎn)進(jìn)行模塊化,從而消除了OOP引起的代碼混亂和分散問(wèn)題,增強(qiáng)了系統(tǒng)的可維護(hù)性和代碼的重用性。本文分析傳統(tǒng)權(quán)限控制的實(shí)現(xiàn)方法,并研究了在AOP下權(quán)限控制的實(shí)現(xiàn)方法。
關(guān)鍵詞 AOP;橫切關(guān)注點(diǎn); 設(shè)計(jì)模式; 權(quán)限控制 OOP應(yīng)用開(kāi)發(fā)面臨的問(wèn)題 面向?qū)ο蠹夹g(shù)很好地解決了軟件系統(tǒng)中角色劃分的問(wèn)題。借助于面向?qū)ο蟮姆治?、設(shè)計(jì)和實(shí)現(xiàn)技術(shù),開(kāi)發(fā)者可以將問(wèn)題領(lǐng)域的“名詞”轉(zhuǎn)換成軟件系統(tǒng)中的對(duì)象,從而很自然地完成從問(wèn)題到軟件的轉(zhuǎn)換。 但是,問(wèn)題領(lǐng)域的某些需求卻偏偏不是用這樣的“名詞”來(lái)描述的。比如遇到這樣的問(wèn)題:需要對(duì)系統(tǒng)中的某些方法進(jìn)行權(quán)限檢驗(yàn),這種需要權(quán)限檢驗(yàn)的方法散布在40多個(gè)類(lèi)中。面對(duì)這種需求,應(yīng)該怎么辦呢?最直接的辦法就是:創(chuàng)建一個(gè)起類(lèi)(或接口),將權(quán)限檢驗(yàn)的功能放在其中,并讓所有需要權(quán)限檢驗(yàn)的類(lèi)繼承這個(gè)起類(lèi)(或接口).如果這個(gè)需求是后期提出的.需要修改的地方就會(huì)分散在40多個(gè)文件中。這樣大的修改量,無(wú)疑會(huì)增加出錯(cuò)的幾率,并且加大系統(tǒng)維護(hù)的難度。 人們認(rèn)識(shí)到,傳統(tǒng)的程序經(jīng)常表現(xiàn)出一些不能自然地適合單個(gè)程序模塊或者幾個(gè)緊密相關(guān)的程序模塊的行為例如權(quán)限檢驗(yàn)、日志記錄、對(duì)上下文敏感的錯(cuò)誤處理、性能優(yōu)化以及設(shè)計(jì)模式等等、我們將這種行為稱(chēng)為“橫切關(guān)注點(diǎn)(crosscuttingconcern)”,因?yàn)樗缭搅私o定編程模型中的典型職責(zé)界限。如果使用過(guò)用于橫切關(guān)注點(diǎn)的代碼,您就會(huì)知道缺乏模塊性所帶來(lái)的問(wèn)題。因?yàn)闄M切行為的實(shí)現(xiàn)是分散的,開(kāi)發(fā)人員發(fā)現(xiàn)這種行為難以作邏輯思維、實(shí)現(xiàn)和更改。 AOP的基本思想 AOP是Aspect Oriented Programming的縮寫(xiě),意思是面向方面編程,一種新興的編程技術(shù)。AOP實(shí)際是GoF設(shè)計(jì)模式的延續(xù),設(shè)計(jì)模式孜孜不倦追求的是調(diào)用者和被調(diào)用者之間的解耦,AOP可以說(shuō)也是這種目標(biāo)的一種實(shí)現(xiàn)。它可以解決OOP和過(guò)程化方法不能夠很好解決的橫切(crosscut)問(wèn)題,如:事務(wù)、安全、日志等橫切關(guān)注。當(dāng)未來(lái)系統(tǒng)變得越來(lái)越復(fù)雜,橫切關(guān)注點(diǎn)就成為一個(gè)大問(wèn)題的時(shí)候,AOP就可以很輕松的解決橫切關(guān)注點(diǎn)這個(gè)問(wèn)題。
通常,為滿(mǎn)足整個(gè)企業(yè)應(yīng)用某方面得需求,開(kāi)發(fā)者(架構(gòu)師)需要整理出系統(tǒng)得關(guān)注點(diǎn)。圖 1形象地描述了關(guān)注點(diǎn),它能夠從AOP Aspect角度看待系統(tǒng)。比如,持久化、日志、應(yīng)用的業(yè)務(wù)邏輯通常被認(rèn)為是應(yīng)用需要解決的問(wèn)題。因此,他們通常作為關(guān)注點(diǎn)看待。從整個(gè)系統(tǒng)角度考慮,它往往是由大量的關(guān)注點(diǎn)構(gòu)成的。 我們把AOP看作是OOP的延續(xù),而不是競(jìng)爭(zhēng)對(duì)手。OOP在通常的場(chǎng)合下工作得很好,但在特定的領(lǐng)域里卻有所欠缺:舉例來(lái)說(shuō),如果我們必須為多個(gè)對(duì)象和方法應(yīng)用相同的事務(wù)行為,我們需要將同樣的代碼剪切/粘貼到每一個(gè)方法里。AOP讓我們可以把這類(lèi)問(wèn)題封裝到方面(aspect)中,從而更好地實(shí)現(xiàn)模塊化。AOP定義了“切入點(diǎn)”(pointcut)的概念,讓開(kāi)發(fā)者可以從另一個(gè)角度來(lái)思考程序的結(jié)構(gòu),從而彌補(bǔ)了OOP的某些缺陷:如果需要對(duì)一組方法施加橫切的行為,就應(yīng)該攔截這些方法。 在J2EE應(yīng)用開(kāi)發(fā)中,我們主要用到AOP的攔截(interception)能力,它為我們提供了“在任何對(duì)象的方法調(diào)用前/后加入自定義行為”的能力,這使得我們可以處理企業(yè)應(yīng)用中的橫切(crosscutting)關(guān)注點(diǎn)(即:同時(shí)作用于多個(gè)對(duì)象的關(guān)注點(diǎn)),并且仍然保持強(qiáng)類(lèi)型(不需要改變方法簽名)。 權(quán)限控制的應(yīng)用程序?qū)崿F(xiàn) 對(duì)于權(quán)限管理的做法,在WEB實(shí)現(xiàn)上,有以下幾種: ?、?利用Filter,對(duì)所有進(jìn)入的URI進(jìn)行解析,并取得當(dāng)時(shí)Session中的User信息,然后通過(guò)RBAC的機(jī)制,將此鏈接需要的權(quán)限與用戶(hù)擁有的權(quán)限進(jìn)行比較,然后進(jìn)行相應(yīng)的處理。這種做法有很多好處:簡(jiǎn)單,容易實(shí)現(xiàn),并且對(duì)系統(tǒng)侵入性也不強(qiáng)。這里URL就是RBAC中的資源了。這樣做的缺點(diǎn)是所有對(duì)數(shù)據(jù)的操作必須通過(guò)URL來(lái)體現(xiàn),這一點(diǎn)在現(xiàn)代的程序中不太好實(shí)現(xiàn)。如果采用Struts, XWork或者Tapestry,采用同一個(gè)URL(瀏覽器看來(lái))進(jìn)行處理多項(xiàng)任務(wù)已不是什么稀奇的事。 ⑵ 利用一個(gè)BaseServlet(Servlet+Jsp經(jīng)典模式)或者BaseAction(Struts模式)或者BasePage(Tapestry模式)或者BaseController(SpringMVC模式),對(duì)所有的請(qǐng)求先進(jìn)行過(guò)濾進(jìn)行權(quán)限操作,然后再處理。稍微看一下就知道這種模式跟Filter并無(wú)本質(zhì)不同。優(yōu)缺點(diǎn)同上。 那么,如果要實(shí)現(xiàn)更為細(xì)致的權(quán)限操作,精確到某個(gè)方法的權(quán)限,典型的做法如下:
這種做法能夠?qū)?quán)限的粒度控制到具體的業(yè)務(wù)方法,因此它的控制能力應(yīng)該是強(qiáng)大的。可以看到,權(quán)限判斷部分對(duì)于每個(gè)方法幾乎是獨(dú)立的。 這種在具體功能前加入權(quán)限操作檢驗(yàn)的實(shí)現(xiàn)方式有很多缺點(diǎn): ⑴ 每個(gè)功能類(lèi)都需要相應(yīng)的權(quán)限檢驗(yàn)代碼,將程序功能和權(quán)限檢驗(yàn)混淆在一起,存在緊密的耦合性,擴(kuò)展修改難度大。 ⑵ 以代理模式為每個(gè)功能類(lèi)實(shí)現(xiàn)一個(gè)相應(yīng)的代理類(lèi),雖然解耦了程序功能和權(quán)限檢驗(yàn),但是,從某個(gè)角色的權(quán)限檢驗(yàn)這個(gè)切面考慮,涉及具體Proxy類(lèi)太多,擴(kuò)展修改難度大。 權(quán)限控制的J2EE容器實(shí)現(xiàn) 在AOP概念沒(méi)有誕生前,J2EE規(guī)范已經(jīng)提供了關(guān)于權(quán)限控制的容器實(shí)現(xiàn)標(biāo)準(zhǔn),這種變遷結(jié)果如下圖所示:
原來(lái)需要每個(gè)應(yīng)用程序?qū)崿F(xiàn)的權(quán)限Proxy轉(zhuǎn)為整個(gè)容器的Proxy實(shí)現(xiàn),其中JDK1.3以后的動(dòng)態(tài)代理API為這種轉(zhuǎn)換實(shí)現(xiàn)提供了技術(shù)保證。 非常明顯,通過(guò)容器實(shí)現(xiàn)權(quán)限控制驗(yàn)證可以大大簡(jiǎn)化應(yīng)用程序的設(shè)計(jì),分離了應(yīng)用系統(tǒng)的權(quán)限關(guān)注,將權(quán)限控制變成了對(duì)J2EE容器服務(wù)器的配置工作。 其實(shí),容器的權(quán)限實(shí)現(xiàn)也是一種從一個(gè)側(cè)面來(lái)解決問(wèn)題方式,AOP概念誕生后,權(quán)限控制實(shí)現(xiàn)由此也帶來(lái)了兩個(gè)方向的變化: ?、拧2EE容器級(jí)別的權(quán)限實(shí)現(xiàn),也就是容器自身的權(quán)限實(shí)現(xiàn)。 ?、啤2EE應(yīng)用程序級(jí)別的權(quán)限實(shí)現(xiàn)。 權(quán)限控制在容器級(jí)別實(shí)現(xiàn)似乎使得J2EE開(kāi)發(fā)者感覺(jué)沒(méi)有靈活性和可擴(kuò)展性,其實(shí)象JBoss 4.0這樣的J2EE容器,由于引入了AOP概念,使得J2EE開(kāi)發(fā)者在自己的應(yīng)用系統(tǒng)中能夠直接操縱容器的一些行為。容器和應(yīng)用系統(tǒng)由于AOP引入的Aspect切面,變得可以成為一體了。 對(duì)于J2EE應(yīng)用系統(tǒng)開(kāi)發(fā)者,能夠做到上述境界,必須的條件是對(duì)JBoss之類(lèi)J2EE容器必須有足夠的了解,因?yàn)檫@些方式并不是J2EE標(biāo)準(zhǔn),有可能在移植到新的J2EE容器,這些知識(shí)和投入變得無(wú)用(也有可能將來(lái)J2EE擴(kuò)展其標(biāo)準(zhǔn))。 很顯然,使用AOP實(shí)現(xiàn)J2EE應(yīng)用系統(tǒng)級(jí)別的權(quán)限控制,是解決上述移植風(fēng)險(xiǎn)的一個(gè)主要方法,但是帶來(lái)的缺點(diǎn)是必須親自從零開(kāi)始做起,耗費(fèi)時(shí)間不會(huì)很短。 AOP下的權(quán)限控制實(shí)現(xiàn) 有了AOP,新的業(yè)務(wù)方法可以這樣寫(xiě):
沒(méi)有了額外的權(quán)限操作,這個(gè)業(yè)務(wù)方法看起來(lái)那么清晰自然。 將對(duì)權(quán)限的操作作為一個(gè)Advice,并將Advisor關(guān)注到所有的業(yè)務(wù)方法(可能有某一個(gè)特定package),然后,剩下的事情就由RBAC以及AOP來(lái)完成了。通過(guò)這樣的分離,縱向的一個(gè)業(yè)務(wù)方法被分割為一個(gè)更為自然的業(yè)務(wù)方法和一個(gè)關(guān)注點(diǎn)。這個(gè)關(guān)注點(diǎn)寫(xiě)法可能如下:
可能有個(gè)問(wèn)題:如何取得context或者當(dāng)時(shí)上下文環(huán)境的User呢?答案是使用IoC(或稱(chēng)Dependency Injection),將上下文環(huán)境或者User作為參數(shù)反向傳入到邏輯方法中。當(dāng)然,在傳入之前,這些變量是需要初始化的。這個(gè)初始化工作可以在SuperServlet中進(jìn)行,并且以Session單例的形式保存在應(yīng)用程序中。下面是Spring配置文件的例子:
結(jié)束語(yǔ) AOP引進(jìn)了Aspect,它將影響多個(gè)類(lèi)的行為封裝到一個(gè)可重用模塊中,它允許程序員對(duì)橫切關(guān)注點(diǎn)進(jìn)行模塊化,從而消除了OOP引起的代碼混亂和分散問(wèn)題,增強(qiáng)了系統(tǒng)的可維護(hù)性和代碼的重用性。利用AOP的攔截(interception)能力,它為我們提供了“在任何對(duì)象的方法調(diào)用前/后加入自定義行為”的能力,這使得我們可以處理企業(yè)應(yīng)用中的權(quán)限控制這一橫切關(guān)注點(diǎn),并且仍然保持強(qiáng)類(lèi)型(不需要改變方法簽名),解耦了程序功能和權(quán)限檢驗(yàn)。 |
|
來(lái)自: 鳳舞天煌 > 《開(kāi)發(fā)模式》