基于新信息技術(shù)的Java-EE應(yīng)用開發(fā)實訓(xùn)教程課件:Spring AOP_第1頁
基于新信息技術(shù)的Java-EE應(yīng)用開發(fā)實訓(xùn)教程課件:Spring AOP_第2頁
基于新信息技術(shù)的Java-EE應(yīng)用開發(fā)實訓(xùn)教程課件:Spring AOP_第3頁
基于新信息技術(shù)的Java-EE應(yīng)用開發(fā)實訓(xùn)教程課件:Spring AOP_第4頁
基于新信息技術(shù)的Java-EE應(yīng)用開發(fā)實訓(xùn)教程課件:Spring AOP_第5頁
已閱讀5頁,還剩23頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

2.1AOP基礎(chǔ)2.2

通知和切面2.1AOP基礎(chǔ)2.1.1AOP概述如圖2-1所示,AOP采用橫向切割的方式,把橫切邏輯,即和業(yè)務(wù)本身無關(guān)的邏輯獨立出來,再根據(jù)需要把這些獨立的模塊織入到業(yè)務(wù)方法中。除了IoC容器,SpringFramework的另一個核心模塊就是AOP框架。但是,Spring的IoC模塊并不依賴于AOP,如果項目中不需要則完全可以不使用AOP模塊。目前,市場上有很多種AOP框架,主流的只有以下三種開源的AOP框架。(1)?AspectJ,5.0版本后與AspectWerkz合并。(2)?JBossAOP,它是JBoss應(yīng)用程序服務(wù)器項目的一個子項目。(3)?SpringAOP,它是SpringFramework的一部分。其中,AspectJ是Java社區(qū)里最完整、最流行的AOP框架。同時,SpringAOP也提供了另外一種完整的AOP實現(xiàn),但它不是AspectJ的競爭者,它的目的是給SpringIoC容器提供一種一致性集成的AOP解決方案。SpringAOP的設(shè)計理念是:無論開發(fā)人員采用什么樣的技術(shù),Spring都會提供一個融合這些技術(shù)的平臺,所以,盡管Spring本身的AOP不是很強(qiáng)大,但是Spring本身提供了對AspectJ的封裝,以支持對AspectJ的使用。2.1.2AOP常用術(shù)語AOP常用術(shù)語見下。(1)?JoinPoint:連接點,在程序執(zhí)行過程中某個特定的點。(2)?PointCut:切入點,匹配連接點(JoinPoint);通知和一個切入點表達(dá)式關(guān)聯(lián),并在滿足這個切入點的連接點上運(yùn)行。(3)?Advice:通知,在切點的某個特定連接點上執(zhí)行的動作,它定義了切面是什么、什么時候使用。(4)?Introduce:引入,可看作是一種特殊的通知,允許為已存在類添加新方法和屬性。例如,可以創(chuàng)建一個稽查通知來記錄對象的最后修改時間。只要用一個方法setLastModified(Date)以及一個保存這個狀態(tài)的變量,即可在不改變已存在類的情況下將狀態(tài)引入,設(shè)置新的行為和狀態(tài)。(5)?Aspect:切面,由切入點和通知組成,它既包括了橫切邏輯的定義,也包括了連接點的定義。(6)?Target:目標(biāo)對象,通知對象織入的目標(biāo)對象,通常這個對象只需要關(guān)注業(yè)務(wù)邏輯操作,非業(yè)務(wù)的橫切邏輯在通知中,AOP可以動態(tài)地把通知織入到這些目標(biāo)中。(7)?Weaving:織入,采用某種方式把通知添加到目標(biāo)對象中的過程。圖2-2展示了AOP的關(guān)鍵概念。2.1.3動態(tài)代理使用代理的目的是不希望客戶直接訪問原始對象,這樣可以起到保護(hù)原始對象的作用,有時也可以屏蔽使用原始對象的細(xì)節(jié)。代理對象負(fù)責(zé)決定是否以及何時將方法調(diào)用轉(zhuǎn)發(fā)到原始對象上,此外,圍繞著每個方法的調(diào)用,代理對象也可以執(zhí)行一些額外任務(wù)。這樣的例子在實際生活中有很多,比如服務(wù)器代理、防火墻代理、代理商等。代理模式是GOF23中經(jīng)典模式之一,其基本思想是給某一對象提供代理對象,并由代理對象控制具體對象的引用。圖2-3展示了代理設(shè)計模式的思路。在Java里,實現(xiàn)代理設(shè)計模式有兩種方法。一種是靜態(tài)代理,另一種是動態(tài)代理。SpringAOP的核心實現(xiàn)技術(shù)是動態(tài)代理。在JDK1.3以后,Java提供了動態(tài)代理技術(shù),允許開發(fā)人員在運(yùn)行期間創(chuàng)建接口的代理實例。使用Java的代理類必須要求目標(biāo)類和代理類實現(xiàn)一個共同的接口。JDK的動態(tài)代理類使用java.lang.reflect包中的兩個主要類:Proxy和InvocationHandler。其中,InvocationHandler是一個接口,可以通過實現(xiàn)該接口定義橫切邏輯,并通過反射的機(jī)制調(diào)用目標(biāo)類代碼,動態(tài)地把橫切邏輯和業(yè)務(wù)邏輯編織在一起。Proxy則是利用InvocationHandler動態(tài)創(chuàng)建一個和目標(biāo)類接口相同的實例,從而產(chǎn)生目標(biāo)類的代理對象。舉例說明,有一個電腦類接口,代碼如下:publicinterfaceComputer{//啟動voidstart();//停止voidstop();//打印voidprint();}接口中有三個方法,分別表示:啟動、停止和打印。接下來,寫一個簡單的實現(xiàn):publicclassPCimplementsComputer{@Overridepublicvoidstart(){System.out.println("啟動電腦...");}@Overridepublicvoidstop(){System.out.println("停止電腦...");}@Overridepublicvoidprint(){System.out.println("打印...");}}ComputerImpl做了一個簡單的實現(xiàn),提示每個方法正在進(jìn)行的操作,現(xiàn)在需要給這個PC類的每個方法添加一個橫切的邏輯,希望在執(zhí)行每個方法之后,打印出該方法運(yùn)行的開始時間和結(jié)束時間。如果采用靜態(tài)代理的方法,則需要另外寫一個靜態(tài)代理類PCStaticProxy,其代碼如下:publicclassPCStaticProxyimplementsComputer{//目標(biāo)類PCpc=newPC();@Overridepublicvoidstart(){System.out.println(newDate()+"開始運(yùn)行!");pc.start();System.out.println(newDate()+"結(jié)束運(yùn)行!"); }@Overridepublicvoidstop(){System.out.println(newDate()+"開始運(yùn)行!");pc.stop();System.out.println(newDate()+"結(jié)束運(yùn)行!");}@Overridepublicvoidprint(){System.out.println(newDate()+"開始運(yùn)行!");pc.print();

System.out.println(newDate()+"結(jié)束運(yùn)行!");} }PCStaticProxy是PC的靜態(tài)代理類實現(xiàn)。PCStaticProxy中有一個pc屬性,這個屬性就是PCStaticProxy要代理的目標(biāo)類,PCStaticProxy所做的就是調(diào)用目標(biāo)類的方法,同時把橫切的代碼織入其中,這樣就完成了對PC類的靜態(tài)代理。在客戶端使用的時候,不再直接使用PC類,而是使用PC的代理類PCStaticProxy。由上面代碼可以看出,使用靜態(tài)代理類實現(xiàn)代碼橫切幾乎要重寫目標(biāo)類代碼,增加了大量的重復(fù)性工作,并且一旦橫切代碼需要改變,就會引起大量的代碼改動,極不利于代碼的維護(hù),若使用動態(tài)代理則不會出現(xiàn)上述問題,下面來看看動態(tài)代理是如何實現(xiàn)的。使用動態(tài)代理類首先需要實現(xiàn)InvocationHandler接口。InvocationHandler接口表示如下:packagejava.lang.reflect;publicinterfaceInvocationHandler{publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable;}接口中聲明方法——invoke(),在方法中控制整個調(diào)用過程。invoke()方法的第一個參數(shù)是最終產(chǎn)生的代理實例,第二個參數(shù)是表示被代理的目標(biāo)實例的方法名,最后一個參數(shù)是表示被調(diào)用的目標(biāo)方法的參數(shù)數(shù)組。事實上,可以將接口看成一個織入器,在invoke方法中,可以把需要織入的橫切代碼和目標(biāo)代碼編織在一起。本例中,創(chuàng)建一個PCHandler類實現(xiàn)接口InvocationHandler:publicclassPCHandlerimplementsInvocationHandler{//代理類Objecttarget;publicPCHandler(Objecttarget){this.target=target;}

@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{Objectobj=null;System.out.println(method.getName()+"于:"+newDate()+"開始運(yùn)行!");obj=method.invoke(this.target,args);System.out.println(method.getName()+"于:"+newDate()+"結(jié)束運(yùn)行!");returnobj;}}該實現(xiàn)類中有一個target屬性,表示需要代理的目標(biāo)類,實現(xiàn)類實例化的時候需要知道這個目標(biāo)類。以下代碼利用了Java中的反射技術(shù)執(zhí)行目標(biāo)類的方法:obj=method.invoke(this.target,args);PCHandler只相當(dāng)于一個代碼織入器,并沒有產(chǎn)生最終的代理類。產(chǎn)生代理類需要使用Proxy類的newInstance方法,其聲明如下:publicstaticObjectnewProxyInstance(ClassLoaderloader,Class<?>[]interfaces,InvocationHandlerh)該方法需要三個參數(shù),第一個參數(shù)負(fù)責(zé)注冊該代理,在絕大部分情況下,它應(yīng)該就是加載原始類的加載器;第二個參數(shù)由該代理需要實現(xiàn)的接口組成,通常需要代理目標(biāo)類的所有接口;第三個參數(shù)傳遞空值,最后用它來進(jìn)行計算,此時所有的方法調(diào)用都將通過日志來處理程序。有了Proxy之后,就可以使用該類創(chuàng)建所需要的代理類給客戶端使用,代碼如下://創(chuàng)建代理目標(biāo)類的實例Computertarget=newPC();//創(chuàng)建Computer的動態(tài)代理Computercomp=(Computer)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),newPCHandler(target));comp.start(); 2.2通?知?和?切?面2.2.1通知SpringAOP主要通過Advice定義橫切邏輯。在Spring中支持5種類型的Advice,這5種類型的Advice如表2-1所示。通常應(yīng)根據(jù)需要實現(xiàn)這些接口中的方法。在接口方法中定義橫切邏輯,就可以把它們織入到目標(biāo)類的方法中,以前置通知為例,使用Spring的AOP方式,給前面定義的PC類的所有方法執(zhí)行加上前置橫切邏輯,并打印“××方法開始執(zhí)行”。首先,實現(xiàn)MethodBeforeAdvice接口,代碼如下:publicclassBeforeAdviceDemoimplementsMethodBeforeAdvice{@Overridepublicvoidbefore(Methodarg0,Object[]arg1,Objectarg2) throwsThrowable{System.out.println(arg0.getName()+"方法執(zhí)行..."); } }MethodBeforeAdvice繼承了BeforeAdvice接口,該接口表示前置通知,需要實現(xiàn)MethodBeforeAdvice接口里面的before方法。before方法有三個參數(shù),其中arg0表示執(zhí)行的目標(biāo)類方法,arg1表示目標(biāo)類方法的參數(shù),arg2表示目標(biāo)實例類。在before方法中,需要定義橫切的邏輯代碼,然后把橫切的代碼與目標(biāo)類代碼編織在一起。在Spring中,需要使用ProxyFactory類產(chǎn)生目標(biāo)類代碼,同時使用它編織橫切代碼。下面看看如何使用ProxyFactory類產(chǎn)生代理類。publicclassBeforeAdviceDemoTest{ publicstaticvoidmain(String[]args) {//獲取Spring代理工廠 ProxyFactorypf=newProxyFactory(); //設(shè)置代理目標(biāo) pf.setTarget(newPC()); //設(shè)置通知 pf.addAdvice(newBeforeAdviceDemo()); //創(chuàng)建代理 PCproxy=(PC)pf.getProxy();

proxy.start(); }}ProxyFactory使用比較簡單,由名字可以看出,它是一個類代理工廠,專門用于產(chǎn)生類代理。Spring會根據(jù)需要使用JDK的代理或者是CGLib的代理,通過ProxyFactory的addAdvice方法可以增加通知。addAdvice方法可以添加多個通知,最終形成通知鏈,調(diào)用的順序和增加通知的順序一致,使用setTarget方法可以指定代理目標(biāo),最后通過getProxy()方法產(chǎn)生一個目標(biāo)類的代理類。除了使用ProxyFactory創(chuàng)建代理外,還可以通過Spring配置IoC的方式產(chǎn)生代理類。使用Spring配置的方式,配置代碼如下:<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.SpringF/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:p="http://www.SpringF/schema/p"

xsi:schemaLocation="http://www.SpringF/schema/beanshttp://www.SpringF/schema/beans/spring-beans-3.0.xsd"><!--advice--><beanid="beforeAdvice"class="com.ssoft.aop.springaop.BeforeAdviceDemo"/><!--target--><beanid="target"class="com.ssoft.aop.dynaproxy.PC"/><!--proxy--><beanid="proxy"class="org.SpringFramework.aop.framework.ProxyFactoryBean"p:interceptorNames="beforeAdvice"p:target-ref="target"p:proxyTargetClass="true"/></beans>在使用配置文件的時候,通知和目標(biāo)對象通過Spring的IoC管理起來,然后用ProxyFactoryBean作為代理對象。配置后,就可以通過實例調(diào)用方法,從Spring容器中獲取代理類的實例,代碼如下:ApplicationContextctx=newClassPathXmlApplicationContext("beans.xml"); PCpc=(PC)ctx.getBean("proxy"); pc.start();其他的通知方式和前置通知類似。對于所有的通知,都可以通過Pointcut切點,把通知有選擇地置入連接點中。2.2.2切面在OOP中模塊化的關(guān)鍵單元是類(classes),而在AOP中模塊化的單元則是切面。切面能對關(guān)注點進(jìn)行模塊化,例如橫切多個類型和對象的事務(wù)管理。Spring提供了3種方式定義和組織切點:編程方式、注解方式和XML配置方式。本小節(jié)以XML配置方式為例,介紹使用切面的方法。用下面的例子來了解一個基于配置方式是如何處理的。<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.SpringF/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:aop="http://www.SpringF/schema/aop"xmlns:p="http://www.SpringF/schema/p"xsi:schemaLocation="http://www.SpringF/schema/beanshttp://www.SpringF/schema/beans/spring-beans-3.0.xsdhttp://www.SpringF/schema/aophttp://www.SpringF/schema/aop/spring-aop-3.0.xsd"><!--target--><beanid="target"class="com.ssoft.aop.dynaproxy.PC"/><!--使用aop配置--><beanid="simpleAdvice"class="com.ssoft.aop.springaop.SimpleAdvice"/><aop:configproxy-target-class="true"><!--配置切面--><aop:aspectref="simpleAdvice"><!--配置切點--><aop:pointcutexpression="execution(*com.ssoft.aop.dynaproxy.PC.*(..))"id="pt1"/><aop:beforemethod="printTime"pointcut-ref="pt1"/></aop:aspect></aop:config></beans>SimpleAdvice類定義如下:publicclassSimpleAdvice{//打印時間 publicvoidprintTime(JoinPointjp){ System.out.println("方法:"+jp.getSignature().getName()+"開始執(zhí)行時間:"+newDate());}}SimpleAdvice是一個普通的類,用于定義橫切邏輯,使用XML配置AOP的時候,橫切邏輯可以是任意一個JavaBean,不需要實現(xiàn)任何接口。要使用XML配置AOP切面,首先需要在beans標(biāo)簽中添加相應(yīng)的命名空間,其次通過一系列的以aop開頭的標(biāo)記配置切面,具體步驟如下:1.聲明切面在Bean配置文件中,所有的SpringAOP配置都必須定義在<aop:config>元素內(nèi)部。每個切面,都要創(chuàng)建一個<aop:aspect>元素來為具體的切面實現(xiàn)引用后端Bean實例。因此,切面Bean必須有一個標(biāo)識符,供<aop:aspect>元素引用。需要注意的是該Bean可以是任意一個簡單的JavaBean,不需要實現(xiàn)任何接口。例如:<aop:configproxy-target-class="true"><!--配置切面--><aop:aspectref="simpleAdvice">…</aop:aspect></aop:config>2.聲明切入點切入點必須定義在<aop:aspect>元素下,或者直接定義在<aop:config>元素下。在前一種情況中,切入點只對聲明的切面可見;而后一種情況則是一個全局的切入點定義,它對所有

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論