Spring Aop之(二)--Aop 切面聲明和通知


6.3.1. 聲明一個切面

有了schema的支持,切面就和常規的Java對象一樣被定義成application context中的一個bean。 對象的字段和方法提供了狀態和行為信息,XML文件則提供了切入點和通知信息。

切面使用<aop:aspect>來聲明,backing bean(支持bean)通過 ref 屬性來引用:

<aop:config>  <aop:aspect id="myAspect" ref="aBean">...  </aop:aspect></aop:config><bean id="aBean" class="...">  ...</bean>

切面的支持bean(上例中的"aBean")可以象其他Spring bean一樣被容器管理配置以及依賴注入。

6.3.2. 聲明一個切入點

切入點可以在切面里面聲明,這種情況下切入點只在切面內部可見。切入點也可以直接在<aop:config>下定義,這樣就可以使多個切面和通知器共享該切入點。

一個描述service層中表示所有service執行的切入點可以如下定義:

<aop:config>  <aop:pointcut id="businessService"expression="execution(* com.xyz.myapp.service.*.*(..))"/></aop:config>

注意切入點表達式本身使用了 Section 6.2, “@AspectJ支持” 中描述的AspectJ 切入點表達式語言。 如果你在Java 5環境下使用基於schema的聲明風格,可參考切入點表達式類型中定義的命名式切入點,不過這在JDK1.4及以下版本中是不被支持的(因為依賴於 Java 5中的AspectJ反射API)。 所以在JDK 1.5中,上面的切入點的另外一種定義形式如下:

<aop:config>  <aop:pointcut id="businessService"expression="com.xyz.myapp.SystemArchitecture.businessService()"/></aop:config>

假定你有 Section 6.2.3.3, “共享常見的切入點(pointcut)定義”中說描述的 SystemArchitecture 切面。

在切面里面聲明一個切入點和聲明一個頂級的切入點非常類似:

<aop:config>  <aop:aspect id="myAspect" ref="aBean"><aop:pointcut id="businessService"  expression="execution(* com.xyz.myapp.service.*.*(..))"/>...  </aop:aspect></aop:config>

當需要連接子表達式的時候,'&'在XML中用起來非常不方便,所以關鍵字'and', 'or' 和 'not'可以分別用來代替'&', '||' 和 '!'。

注意這種方式定義的切入點通過XML id來查找,並且不能定義切入點參數。在基於schema的定義風格中命名切入點支持較之@AspectJ風格受到了很多的限制。

6.3.3. 聲明通知

和@AspectJ風格一樣,基於schema的風格也支持5種通知類型並且兩者具有同樣的語義。

6.3.3.1. 通知(Advice)

Before通知在匹配方法執行前進入。在<aop:aspect>里面使用<aop:before>元素進行聲明。

<aop:aspect id="beforeExample" ref="aBean"><aop:before  pointcut-ref="dataAccessOperation"  method="doAccessCheck"/>...</aop:aspect>

這里 dataAccessOperation 是一個頂級(<aop:config>)切入點的id。 要定義內置切入點,可將 pointcut-ref 屬性替換為 pointcut 屬性:

<aop:aspect id="beforeExample" ref="aBean"><aop:before  pointcut="execution(* com.xyz.myapp.dao.*.*(..))"  method="doAccessCheck"/>...</aop:aspect>

我們已經在@AspectJ風格章節中討論過了,使用命名切入點能夠明顯的提高代碼的可讀性。

Method屬性標識了提供了通知的主體的方法(doAccessCheck)。這個方法必須定義在包含通知的切面元素所引用的bean中。 在一個數據訪問操作執行之前(執行連接點和切入點表達式匹配),切面中的"doAccessCheck"會被調用。

6.3.3.2. 返回后通知(After returning advice)

After returning通知在匹配的方法完全執行后運行。和Before通知一樣,可以在<aop:aspect>里面聲明。例如:

<aop:aspect id="afterReturningExample" ref="aBean"><aop:after-returning  pointcut-ref="dataAccessOperation"  method="doAccessCheck"/>...</aop:aspect>

和@AspectJ風格一樣,通知主體可以接收返回值。使用returning屬性來指定接收返回值的參數名:

<aop:aspect id="afterReturningExample" ref="aBean"><aop:after-returning  pointcut-ref="dataAccessOperation"  returning="retVal"  method="doAccessCheck"/>...</aop:aspect>

doAccessCheck方法必須聲明一個名字叫 retVal 的參數。 參數的類型強制匹配,和先前我們在@AfterReturning中講到的一樣。例如,方法簽名可以這樣聲明:

public void doAccessCheck(Object retVal) {...

6.3.3.3. 拋出異常后通知(After throwing advice)

After throwing通知在匹配方法拋出異常退出時執行。在 <aop:aspect> 中使用after-throwing元素來聲明:

<aop:aspect id="afterThrowingExample" ref="aBean"><aop:after-throwing  pointcut-ref="dataAccessOperation"  method="doRecoveryActions"/>...</aop:aspect>

和@AspectJ風格一樣,可以從通知體中獲取拋出的異常。 使用throwing屬性來指定異常的名稱,用這個名稱來獲取異常:

<aop:aspect id="afterThrowingExample" ref="aBean"><aop:after-throwing  pointcut-ref="dataAccessOperation"  thowing="dataAccessEx"  method="doRecoveryActions"/>...</aop:aspect>

doRecoveryActions方法必須聲明一個名字為 dataAccessEx 的參數。 參數的類型強制匹配,和先前我們在@AfterThrowing中講到的一樣。例如:方法簽名可以如下這般聲明:

public void doRecoveryActions(DataAccessException dataAccessEx) {...

6.3.3.4. 后通知(After (finally) advice)

After (finally)通知在匹配方法退出后執行。使用 after 元素來聲明:

<aop:aspect id="afterFinallyExample" ref="aBean"><aop:after  pointcut-ref="dataAccessOperation"  method="doReleaseLock"/>...</aop:aspect>

6.3.3.5. 通知

Around通知是最后一種通知類型。Around通知在匹配方法運行期的“周圍”執行。 它有機會在目標方法的前面和后面執行,並決定什么時候運行,怎么運行,甚至是否運行。 Around通知經常在需要在一個方法執行前或后共享狀態信息,並且是線程安全的情況下使用(啟動和停止一個計時器就是一個例子)。 注意選擇能滿足你需求的最簡單的通知類型(i.e.如果簡單的before通知就能做的事情絕對不要使用around通知)。

Around通知使用 aop:around 元素來聲明。 通知方法的第一個參數的類型必須是 ProceedingJoinPoint 類型。 在通知的主體中,調用 ProceedingJoinPointproceed() 方法來執行真正的方法。 proceed 方法也可能會被調用並且傳入一個 Object[] 對象 - 該數組將作為方法執行時候的參數。 參見 Section 6.2.4.5, “環繞通知(Around Advice)” 中提到的一些注意點。

<aop:aspect id="aroundExample" ref="aBean"><aop:around  pointcut-ref="businessService"  method="doBasicProfiling"/>...</aop:aspect>

doBasicProfiling 通知的實現和@AspectJ中的例子完全一樣(當然要去掉注解):

public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {    // start stopwatch    Object retVal = pjp.proceed();    // stop stopwatch    return retVal;}
<aop:config proxy-target- class= " true " >
        <aop:aspect id= " aop_aspect_frisetclass "   ref= " AopAdvice ">
                <!-- 定義個After增強處理,直接指定切入點表達式,以切面 Bean 中的 Release() 方法作為增強處理方法 -->  
                <aop:around pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.*(..)) " method= " doBasicProfiling " />
                <aop:before pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.addStudent(..)) " method= " aopbeforemethod "/>
                  <aop:after pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.addStudent(..)) " method= " aopaftermethod "/>
                  <aop:after-returning pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.getStudentScores(..)) "  returning= " val " method= " aopafterreturnmethod "/>
                  <aop:after-throwing pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.getStudentScores(..)) "  throwing= " exdate "  method= " aopafterthrowmethod "/>
        </aop:aspect>
    </aop:config>

 

public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {   
         //  start stopwatch   
        Object retVal = pjp.proceed();   
         if(pjp.getArgs()!= null){
             for(Object o : pjp.getArgs()){
                
                logger.debug( " 參賽= "+o);
                
            }
        }
         //  stop stopwatch   
         return retVal;
    }
     public  void aopbeforemethod(){
        logger.debug( " 執行  方法 aopbeforemethod  ");
    }
     public  void aopaftermethod(){
    
    }
     public  void aopafterreturnmethod(Object val){
        logger.debug( " 執行  方法 aopafterreturnmethod  返回值 "+val);
    }
     public  void aopafterthrowmethod(Throwable  exdate){
        logger.debug( " 執行  方法 aopafterthrowmethod  "+exdate);
    }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM