專利名稱:一種基于動態(tài)棧的ejb3 容器aop 實現(xiàn)方法
一種基于動態(tài)棧的EJB3容器AOP實現(xiàn)方法技術(shù)領(lǐng)域
本發(fā)明提出了 Java EE系統(tǒng)架構(gòu)下一種基于動態(tài)棧的實現(xiàn)EJB3業(yè)務(wù)方法攔截的方法。該方法結(jié)合預(yù)編譯和動態(tài)棧的方式分別處理系統(tǒng)級別和業(yè)務(wù)方法級別的攔截器方法,提高了 EJB容器對業(yè)務(wù)方法攔截的速度與靈活性。
背景技術(shù):
AOP 為 Aspect Oriented Programming 的縮寫,即面向切面編程。
AOP技術(shù)利用一種稱為“橫切”的技術(shù),剖解開封裝的對象內(nèi)部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,并將其名為“Aspect”,即方面,也就是將那些與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護(hù)性。
使用“橫切”技術(shù),AOP把軟件系統(tǒng)分為兩個部分核心關(guān)注點和橫切關(guān)注點。業(yè)務(wù)處理的主要流程是核心關(guān)注點,與之關(guān)系不大的部分是橫切關(guān)注點。橫切關(guān)注點的一個特點是,他們經(jīng)常發(fā)生在核心關(guān)注點的多處,而各處都基本相似。比如權(quán)限認(rèn)證、日志、事務(wù)處理。AOP的目的就是將核心關(guān)注點和橫切關(guān)注點分離。
EJB3. 0引入了 AOP中的攔截器概念,指出程序員可以在業(yè)務(wù)方法的執(zhí)行前后加入其他非核心業(yè)務(wù)方法即攔截器方法。攔截器是可以對bean的業(yè)務(wù)方法和生命周期事件進(jìn)行攔截的組件,在這些方法被訪問之前,進(jìn)行攔截然后在之前或之后加入某些操作。
但是為什么要在EJB3規(guī)范中引入攔截器呢?從前面的敘述可知攔截器是面向切面編程的一部分,切面可以看成是關(guān)注點,比如在執(zhí)行主要的商業(yè)邏輯代碼之前所做的事務(wù)、安全等操作,這些操作雖然比較普通,但是也會貫穿整個程序的始終,使得程序代碼中充斥著大量相同的代碼,不僅削弱了代碼的可讀性,而且也給應(yīng)用程序的開發(fā)和維護(hù)帶來不必要的麻煩。有了攔截器之后,就可以攔截主要的業(yè)務(wù)邏輯,把非業(yè)務(wù)邏輯的代碼“注入” 到里面去,實現(xiàn)業(yè)務(wù)邏輯代碼和相對不重要的安全、日志等代碼的分離開來,提高應(yīng)用程序的可維護(hù)性和可讀性。
目前實現(xiàn)AOP的技術(shù),主要分為兩大類一是采用動態(tài)代理技術(shù),利用截取消息的方式,動態(tài)生成原有對象的代理對象以取代原有對象行為的執(zhí)行;二是采用靜態(tài)織入的方式,引入特定的語法創(chuàng)建“方面”,從而使得編譯器可以在編譯期間織入有關(guān)“方面”的代碼。 當(dāng)前Java平臺下實現(xiàn)了 AOP的主流項目主要有AspectJ、JBoss、Spring。
預(yù)編譯方式的代表是AspectJ。AspectJ采用了在預(yù)編譯過程中重新生成源代碼的方式,有自己專門的編譯器和AOP語法,但AspectJ沒有利用反射技術(shù)或代理技術(shù),而僅僅是程序的靜態(tài)擴展而已。然而這種源代碼生成方式實現(xiàn)的AOP雖然在性能上具備一定的優(yōu)勢,但它過于復(fù)雜,修改源代碼的侵入式編程破壞了原來代碼的結(jié)構(gòu)性,給開發(fā)帶來一定的問題。
JBoss和Spring的AOP都實現(xiàn)利用了 JDK提供的動態(tài)代理技術(shù)。當(dāng)攔截到業(yè)務(wù)方法的請求時,根據(jù)業(yè)務(wù)方法需要執(zhí)行的攔截器元數(shù)據(jù)信息,依次生成代理類ft~0Xy,并且形成一條鏈?zhǔn)浇Y(jié)構(gòu),依次執(zhí)行這些攔截器方法。 發(fā)明內(nèi)容
本發(fā)明的目的在于克服預(yù)編譯和動態(tài)代理兩種方式AOP實現(xiàn)的缺陷,提供了一種基于動態(tài)棧的EJB3容器AOP實現(xiàn)方式,使用預(yù)編譯和動態(tài)棧兩種方式相結(jié)合的方式來實現(xiàn) EJB容器對業(yè)務(wù)方法的攔截。針對如日志、事務(wù)管理和安全等系統(tǒng)服務(wù)對所有的EJB處理方式一致的特點,將相應(yīng)代碼通過預(yù)編譯方式重新生成源代碼,減少了處理攔截器請求的時間,并通過配置文件的方式使得盡量減少對源代碼的侵入式修改。對于EJB的業(yè)務(wù)方法攔截器,考慮到程序員經(jīng)常修改編輯攔截器類的特點,采用動態(tài)棧的方式避免了預(yù)編譯反復(fù)生成源代碼的缺陷;同時相比動態(tài)代理方式節(jié)約了大量生成動態(tài)代理類的內(nèi)存空間。使用靜態(tài)和動態(tài)相結(jié)合提高EJB容器對業(yè)務(wù)方法攔截的速度與靈活性。
為達(dá)到上述目的,本發(fā)明采用的技術(shù)方案是
根據(jù)攔截器方法作用和性質(zhì)的不同,將攔截器方法分為系統(tǒng)級別和業(yè)務(wù)邏輯級別兩種類型,分別采用預(yù)編譯和動態(tài)棧的方式處理EJB3相應(yīng)的攔截器方法。
1)預(yù)編譯方式處理系統(tǒng)級別攔截器方法
EJB容器分離了一般應(yīng)用系統(tǒng)的一些通用功能,例如事務(wù)機制、安全機制以及對象池或線程池等性能優(yōu)化機制,這些功能是每個應(yīng)用系統(tǒng)幾乎都需要的,因此可以從具體應(yīng)用系統(tǒng)中分離出來。系統(tǒng)級別的攔截器方法主要就是指對EJB的日志、安全和事務(wù)管理等通用功能,將這類的攔截器方法交由EJB容器執(zhí)行,這對簡化EJB的開發(fā)、維護(hù)EJB運行的穩(wěn)定性和快速性都很非常重要。
通過預(yù)編譯的方式將這類方法織入源代碼中,在業(yè)務(wù)方法的執(zhí)行前和執(zhí)行后插入相應(yīng)的預(yù)處理和后處理系統(tǒng)級別攔截器方法調(diào)用即可完成系統(tǒng)功能方法和業(yè)務(wù)邏輯方法的分離和攔截。
當(dāng)EJB容器要管理的系統(tǒng)級別攔截功能很多的時候,預(yù)編譯的速度會相應(yīng)降低。 在EJB容器要管理的系統(tǒng)級別攔截功能變動或修改很大的情況下,預(yù)編譯的模板還要做繁瑣的修改,這就給預(yù)編譯方式帶來了不便。
因此,為預(yù)編譯織入的代碼提供統(tǒng)一的接口,簡化預(yù)編譯的過程尤為重要。按照 EJB容器提供的系統(tǒng)級別攔截器功能執(zhí)行的先后次序,利用反射機制將這些方法依次入棧和出棧,通過彈棧的方式依次執(zhí)行位于棧頂?shù)姆椒ǎ蟠鬁p輕了維護(hù)編譯模板的壓力;同時盡量減小了對源代碼的修改,提高了預(yù)編譯的速度。
2)動態(tài)棧方式處理業(yè)務(wù)邏輯級別攔截器方法
EJB3規(guī)范指出程序員除了可以使用系統(tǒng)級別攔截器之外,還可以自定義業(yè)務(wù)方法攔截器和生命周期攔截器,這兩種統(tǒng)稱為“業(yè)務(wù)邏輯攔截器”。
和由EJB容器管理的實現(xiàn)通用功能的系統(tǒng)級別攔截器方法相比,EJB的業(yè)務(wù)邏輯攔截器由程序員維護(hù)。程序員經(jīng)常需要修改編輯攔截器類和方法,如果采用預(yù)編譯方式需要不停的往EJB源代碼中織入不同的代碼,造成的后果就是一個很小的改動需要花費很大的預(yù)編譯代價,增大了開發(fā)的負(fù)擔(dān)。
如果采用當(dāng)前大多數(shù)應(yīng)用服務(wù)器所使用的動態(tài)代理方式,為EJB的每個業(yè)務(wù)邏輯級別攔截器類都生成了一個動態(tài)代理類,按照調(diào)用的先后順序形成了動態(tài)代理類鏈。雖然動態(tài)代理方式可以避免預(yù)編譯反復(fù)生成源代碼的缺點,但也有如下缺陷。動態(tài)代理類是運行時生成的類,消耗一定的內(nèi)存空間;而且動態(tài)代理類不會做任何實質(zhì)性的工作,它只能攔截到業(yè)務(wù)方法的調(diào)用請求,將調(diào)用轉(zhuǎn)給一個調(diào)用請求的處理類,而這個類也必須是調(diào)用者提供。
使用動態(tài)棧的方式避免了這兩者的缺陷,既不需要將業(yè)務(wù)邏輯級別的攔截器方法通過預(yù)編譯織入源代碼中也不需要像動態(tài)代理方式一樣生成動態(tài)代理類和提供實現(xiàn)了調(diào)用請求的處理類。
攔截到業(yè)務(wù)方法調(diào)用之后,根據(jù)解析的EJB的元數(shù)據(jù)中相關(guān)的自定義攔截器類和方法的信息,按照要求的順序?qū)r截器方法依次入棧。將方法棧和業(yè)務(wù)方法的信息封裝成一個調(diào)用上下文hvocationContext傳遞給第一個執(zhí)行的攔截器方法。每個攔截器方法體都分為三部分首先是業(yè)務(wù)方法執(zhí)行前的預(yù)處理代碼,其次是業(yè)務(wù)方法執(zhí)行后的后處理代碼,在預(yù)處理和后期處理之間,執(zhí)行后續(xù)的攔截器方法。具體執(zhí)行后續(xù)攔截器方法的步驟為彈出棧頂攔截器方法,并將彈出棧頂攔截器方法的棧和業(yè)務(wù)方法的信息重新封裝成 hvocationContext傳給該方法,最后通過反射機制調(diào)用該方法。后續(xù)攔截器方法執(zhí)行返回之后,本攔截器方法可以繼續(xù)執(zhí)行后續(xù)的后處理工作了。
圖1是預(yù)編譯源文件的接口示意圖。
圖2是解析EJB攔截器元數(shù)據(jù)并將其壓棧后棧內(nèi)結(jié)構(gòu)示意圖。
圖3是假定的某業(yè)務(wù)方法的棧內(nèi)結(jié)構(gòu)示意圖。
圖4是在圖2的情況下預(yù)編譯與動態(tài)棧相結(jié)合協(xié)作執(zhí)行系統(tǒng)級別和業(yè)務(wù)邏輯級別攔截器方法時序圖。
具體實施方式
下面結(jié)合附圖對本發(fā)明作進(jìn)一步說明。
1)預(yù)編譯方式處理系統(tǒng)級別攔截器方法
EJB從類型劃分,可分為無狀態(tài)會話bean、有狀態(tài)會話bean、實體bean和消息驅(qū)動bean ;從事務(wù)管理類型還可以分為BMT (bean管理實務(wù))和CMT (容器管理事務(wù));每種不同分類的組合都有自己特定的預(yù)處理方式,可以通過為不同的分類定制不同的預(yù)編譯基類,并讓這些預(yù)編譯的基類都實現(xiàn)預(yù)編譯接口從而達(dá)到簡化預(yù)處理過程中對源代碼修改的簡化或者盡量不修改源代碼。
預(yù)編譯事實上并不修改源文件以防止修改源代碼的侵入式編程破壞了原來代碼的結(jié)構(gòu)性。相反,預(yù)編譯按照源文件類繼承的接口生成了新的編譯后文件。這個編譯后文件創(chuàng)建源文件類的對象,在攔截到調(diào)用請求后,激活對象相應(yīng)的方法。
如圖1是預(yù)編譯源文件的接口,可以看到所有實現(xiàn)了預(yù)編譯接口的基類都需要實現(xiàn)executePreSysInter^ptor (執(zhí)行業(yè)務(wù)方法調(diào)用前的系統(tǒng)級別攔截器方法)、 executeMethod(執(zhí)行業(yè)務(wù)方法)、executePostSysInterc印tor (執(zhí)行業(yè)務(wù)方法調(diào)用后的系統(tǒng)級別攔截器方法)。預(yù)編譯后文件中方法結(jié)構(gòu)為
首先是該類的父類也即是預(yù)編譯基類中的I^eSyshterc印tor方法;其次是封裝當(dāng)前方法的方法名和參數(shù),并將它們作為參數(shù)傳給父類的executeMethod方法;最后它的父類也即是預(yù)編譯基類中的PostSysInterc印tor方法。
從中也可以看到每個方法體內(nèi)這三個方法的執(zhí)行順序,編譯后的源文件并沒有修改實際執(zhí)行的代碼。它將請求轉(zhuǎn)交給預(yù)編譯的基類,并由該基類來實現(xiàn)系統(tǒng)級別攔截器方法對執(zhí)行代碼的前后處理。
執(zhí)行業(yè)務(wù)方法調(diào)用前后系統(tǒng)級別攔截器方法的步驟如下
1、在配置文件中配置各種不同類別的EJB所需要使用的系統(tǒng)功能。
2、EJB容器啟動時讀取這些配置信息。
3、客戶端按照J(rèn)NDI查找EJB時,返回相應(yīng)編譯后文件的對象。
4、調(diào)用業(yè)務(wù)方法時,按照配置信息將系統(tǒng)級別攔截器方法中的預(yù)處理依次壓入一個棧中。
5、每次彈出位于棧頂?shù)臄r截器方法,執(zhí)行它,結(jié)束之后再彈出棧頂方法,直至棧為空。
6、調(diào)用源文件類對象中的對應(yīng)業(yè)務(wù)方法,保存執(zhí)行結(jié)果。
7、按照配置信息將系統(tǒng)級別攔截器方法中的后處理依次壓入一個棧中,采用和預(yù)處理方法相同方法執(zhí)行。
8、將執(zhí)行結(jié)果返回給客戶端。
2)動態(tài)棧方式處理業(yè)務(wù)邏輯級別攔截器方法
EJB3規(guī)范根據(jù)作用范圍可以將EJB的攔截器類分為如下四種缺省攔截器類,自動作用于所有EJB的所有業(yè)務(wù)邏輯方法和生命周期方法;類級攔截器類,作用于指定的EJB 的所有業(yè)務(wù)邏輯方法和生命周期方法;方法級攔截器類,只作用于所指定的某個EJB的特定業(yè)務(wù)方法,不能用于攔截bean的生命周期事件;bean級攔截器類,又被稱為自我攔截器, 只能作用于該EJB本身。
bean的每個業(yè)務(wù)方法和生命周期方法之上都會有很多個攔截器類,每個攔截器類都有且僅有一個攔截器方法,在攔截發(fā)生時它會按照一定的順序調(diào)用這些攔截器方法,最終執(zhí)行指定的業(yè)務(wù)或生命周期方法。
攔截器方法的執(zhí)行順序受到攔截器類的優(yōu)先級和繼承關(guān)系的約束。一般來說,定義在外部類的攔截器執(zhí)行的優(yōu)先級比定義在Bean類中的攔截器要高;缺省攔截器類的優(yōu)先級大于類級攔截器類的優(yōu)先級,類級攔截器類的優(yōu)先級大于方法級攔截器類的優(yōu)先級, 方法級攔截器類的優(yōu)先級又大于bean級攔截器類的優(yōu)先級;父類攔截器的優(yōu)先級大于子類攔截器類的優(yōu)先級;bean級攔截器類的父類即EJB父類攔截器方法的優(yōu)先級大于EJB中定義的攔截器方法的優(yōu)先級;同級別的攔截器類的攔截器方法按照配置文件或者標(biāo)注中定義的順序執(zhí)行。
如圖2所示是將各攔截器壓棧后的結(jié)構(gòu)示意圖。壓棧和之后執(zhí)行攔截器方法及業(yè)務(wù)方法的算法如下所示(設(shè)置棧Si用于存儲調(diào)用攔截器類的順序)
1、按照攔截器類的執(zhí)行順序,將最后執(zhí)行攔截器方法的攔截器類壓入棧Si,依次是將剩下的攔截器類中最后執(zhí)行攔截器方法的攔截器類壓入棧Si,則棧Sl的棧頂是優(yōu)先級最高的攔截器類。
2、根據(jù)業(yè)務(wù)方法的方法名、定義方法的EJB類名、方法傳入的實參、方法返回類型等內(nèi)容構(gòu)造一個InvocationContext實例設(shè)為ctx。
3、判斷Sl是否為空,如果是,則執(zhí)行業(yè)務(wù)邏輯方法,轉(zhuǎn)4 ;否則彈出棧頂攔截器類設(shè)為P,調(diào)用P的攔截器方法并將Ctx作為參數(shù)傳給攔截器方法,在P的攔截器方法執(zhí)行過程中會執(zhí)行到Ctx. proceed()這一步,在Invocation, proceed()方法內(nèi)部執(zhí)行執(zhí)行3。
4、攔截器方法一層層返回,直至優(yōu)先級最高的攔截器類的攔截器方法執(zhí)行完畢。
圖3是假定的某業(yè)務(wù)方法的棧內(nèi)結(jié)構(gòu),圖4是在圖2的情況下預(yù)編譯與動態(tài)棧相結(jié)合協(xié)作執(zhí)行系統(tǒng)級別和業(yè)務(wù)邏輯級別攔截器方法時序圖,從中可以看到整個業(yè)務(wù)方法調(diào)用截器方法的執(zhí)行過程。
權(quán)利要求
1.一種基于動態(tài)棧的EJB3容器AOP實現(xiàn)方法,其特征在于根據(jù)攔截器方法作用和性質(zhì)的不同,將攔截器方法分為系統(tǒng)級別攔截器方法和業(yè)務(wù)邏輯級別攔截器方法兩種類型, 分別采用預(yù)編譯和動態(tài)棧的方式處理EJB3相應(yīng)的攔截器方法;1)預(yù)編譯方式處理系統(tǒng)級別攔截器方法在業(yè)務(wù)方法的執(zhí)行前和執(zhí)行后插入相應(yīng)的預(yù)處理和后處理系統(tǒng)級別攔截器方法調(diào)用步驟,完成系統(tǒng)功能方法和業(yè)務(wù)邏輯方法的分離和攔截;向上述調(diào)用步驟提供統(tǒng)一的數(shù)據(jù)接口,通過配置文件的方式指明需要使用的系統(tǒng)功能方法及其調(diào)用次序,結(jié)合EJB3容器提供的系統(tǒng)級別攔截器功能執(zhí)行的先后次序,利用反射機制將這些方法依次入棧和出棧,通過彈棧的方式依次執(zhí)行位于棧頂?shù)姆椒ǎ?)動態(tài)棧方式處理業(yè)務(wù)邏輯級別攔截器方法攔截到業(yè)務(wù)方法調(diào)用之后,根據(jù)解析的EJB的元數(shù)據(jù)中相關(guān)的自定義攔截器類和方法的信息,按照要求的順序?qū)I(yè)務(wù)邏輯級別攔截器方法依次入棧;執(zhí)行時,首先彈出棧頂元素的攔截器方法,將方法棧和業(yè)務(wù)方法的信息封裝成一個調(diào)用上下文hvocationContext傳遞給第一個執(zhí)行的業(yè)務(wù)邏輯級別攔截器方法;每個業(yè)務(wù)邏輯級別攔截器方法體都分為三步首先是業(yè)務(wù)方法執(zhí)行前的預(yù)處理;其次是執(zhí)行后續(xù)的業(yè)務(wù)邏輯級別攔截器方法或者業(yè)務(wù)方法;最后是業(yè)務(wù)方法執(zhí)行后的后處理;執(zhí)行后續(xù)的攔截器方法之后,當(dāng)前攔截器方法繼續(xù)執(zhí)行后處理工作;這樣就會在JVM 中形成一個調(diào)用攔截器方法的動態(tài)棧,這個棧在業(yè)務(wù)方法最終執(zhí)行前會不斷添加新的調(diào)用攔截器方法,并在業(yè)務(wù)方法執(zhí)行完畢后不斷有調(diào)用攔截器方法返回,直至返回到步驟1)中攔截到業(yè)務(wù)方法調(diào)用請求的地方。
2.根據(jù)權(quán)利要求1所述的方法,其特征在于具體執(zhí)行后續(xù)的業(yè)務(wù)邏輯級別攔截器方法或者業(yè)務(wù)方法的步驟為若從上述hvocationContext判斷得到棧不為空,則彈出棧頂攔截器方法作為接下來要執(zhí)行的攔截器方法,并將彈出棧頂攔截器方法的棧和業(yè)務(wù)方法的信息重新封裝成hvocationContext傳給下一個攔截器方法,最后通過反射機制調(diào)用下一個攔截器方法;否則,棧為空,從hvocationContext獲取業(yè)務(wù)方法,然后執(zhí)行該業(yè)務(wù)方法。
全文摘要
一種基于動態(tài)棧的EJB3容器AOP實現(xiàn)方式,使用預(yù)編譯和動態(tài)棧兩種方式相結(jié)合的方式來實現(xiàn)EJB容器對業(yè)務(wù)方法的攔截。針對如日志、事務(wù)管理和安全等系統(tǒng)服務(wù)對所有的EJB處理方式一致的特點,將相應(yīng)代碼通過預(yù)編譯方式重新生成源代碼,減少了處理攔截器請求的時間,并通過配置文件的方式使得盡量減少對源代碼的侵入式修改。對于EJB的業(yè)務(wù)方法攔截器,考慮到程序員經(jīng)常修改編輯攔截器類的特點,采用動態(tài)棧的方式避免了預(yù)編譯反復(fù)生成源代碼的缺陷;同時相比動態(tài)代理方式節(jié)約了大量生成動態(tài)代理類的內(nèi)存空間。使用靜態(tài)和動態(tài)相結(jié)合提高EJB容器對業(yè)務(wù)方法攔截的速度與靈活性。
文檔編號G06F9/45GK102508668SQ20111035778
公開日2012年6月20日 申請日期2011年11月11日 優(yōu)先權(quán)日2011年11月11日
發(fā)明者楊濤, 王培培, 郝瑩耀, 齊勇 申請人:西安交通大學(xué)