spring學習筆記(五)

Advice詳解

         前面提到了,一個切面由一個PointCut和一個Advice組成,Advice主要包含了橫切代碼以及,織入位置的部分信息(即織入PointCut給定方法的方法的前面、後面、前面和後面、異常拋出時、添加一些新的方法和屬性)。java

         針對上面的位置信息,Spring提供了5種對應的子接口:前置加強、後置加強、環繞加強、異常拋出加強、引介加強。spring

(1)       前置加強:

        Spring提供了org.springframework.aop.BeforeAdvice接口,可是由於Spring如今只支持方法級別的加強,因此MethodBeforeAdvice是當前可用的前置加強,表示在目標方法執行前實施加強,估計之後還會有其餘的前置加強,敬請期待。數組

例子:學習

Person.java

public interface Person {
    public void sleep() ;
}

下面是一個懶人的睡覺方式測試

LazyPerson.java

public class LazyPerson implements Person {
    public void sleep() {
        System.out.println("I am sleeping.....ZZZZ");
    }
}

咱們但願在睡覺前先完成洗漱,下面使用Advice使其睡覺前先洗漱spa

GreetingBeforeAdvice.java
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("I am washing face.....");
    }
}

實現MethodBeforeAdvice接口,實現before方法,這個方法中的代碼就是橫切代碼,參數分別是PointCut提供的目標方法對象(沒有PointCut提供默認爲類中的全部方法將遍歷入參)、方法在調用時傳入的參數數組、目標類對象。代理

當該方法發生異常時,將阻止目標類執行code

下面使用Spring提供的ProxyFactory和測試類來驗證效果orm

BeforeAdviceTest.java

public class BeforeAdviceTest {
    private Person target;
    private BeforeAdvie advice;
    private ProxyFactory pf;
    
    @BeforeTest
    public void init() {
        target = new LazyPerson();
        advice = new GreetingBeforeAdvice();
        pf = new ProxyFactory();
        pf.setTarget(target);
        pf.addAdvice(advice);
    }
    
    @Test
    public void beforeAdvice() {
        Person proxy = (Person)pf.getProxy;
        proxy.sleep();    
    }
}

運行上面代碼,將輸出xml

I am washing face.....
I am sleeping.....ZZZZ

        看到這裏可能有讀者會說了,只是加一句簡單的控制檯打印代碼有必要寫的這麼複雜嗎?因此這裏聲明一下,上面的例子並非很形象,若是隻是像上面同樣加一些簡單代碼徹底能夠單獨提出一個方法,這個例子只是爲了展現Advice的用法,同時這裏也突出了一個問題,咱們能夠發現並非任什麼時候候使用Spring Aop都是好的,他也會增長咱們代碼的複雜度,因此用的時候請想清楚使用Aop是否合適。還有這裏的例子代碼都沒有通過真實的運行測試,但願學習的朋友請本身動手寫下代碼,有問題能夠提出來討論,下面的例子也有相同問題,請勿怪。

        Spring配置文件中使用代理:

<bean id="advice" class="GreetingBeforeAdvice"/>
<bean id="target" class="LazyPerson"/>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:proxyInterfaces="person"
    p:interceptorNames="advice"
    p:target-ref="target"/>

ProxyFactoryBean負責爲其餘Bean建立代理實例,內部使用ProxyFactory完成這個工做,ProxyFactoryBean的可配置屬性以下:

  • target:代理的目標對象

  • proxyInterfaces:代理所要實現的接口,能夠爲多借口

  • interceptorNames:須要織入目標對象的Bean列表,採用Bean的名稱指定,這些Bean必須實現MethodInterceptor或Advisor,配置順序對應調用順序

  • singleton:返回對象是否爲單例,默認是

  • optimize:當爲true,強制使用CGLIB代理,對應單例推薦使用CGLIB代理,其餘用JDK代理,由於CGLIB代理建立慢,但建立出的代理對象運行效率快,JDK相反

  • proxyTargetClass:是否使用類代理(不使用接口代理),true時使用CGLIB代理

(2)       後置加強

    Spring提供了org.springframework.aop.AfterReturningAdvice目標方法執行後實施加強

        實現AfterReturningAdvice接口,實現afterReturning(Object returnObj, Method method, Object[] args, Object obj) throws Throwable方法,returnObj是方法返回結果,其餘與前置加強同樣。

        還有一點與前置加強區別,當發生異常時,若是異常是目標方法聲明的異常,異常將歸併到目標方法,不然將異常轉換成運行期異常拋出。

        因爲後置加強與前置用法相識,這裏就不寫例子了

(3)    環繞加強

        Spring提供org.aoplliance.intercept.MethodInterceptor目標方法執行先後實施加強

        

GreetingInterceptor.java

public class GreetingInterceptor implements MethodInterceptor {
    //實現如下方法
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object[] args = invocation.getArguments();//目標方法入參
        //TO-DO 目標方法執行前須要執行的代碼
        Object obj = invocation.proceed();//反射調用目標方法
        //TO-DO 目標方法執行後須要執行的代碼
        return obj;        
    }
}

(4)    異常拋出加強

        Spring提供了org.springframework.aop.ThrowsAdvice表示在目標方法拋出異常後實施加強

        異常拋出加強最適合是事物的回滾操做,在ThrowsAdvice接口中並無定義任何的抽象方法,他只是一個標識接口,在運行期間Spring會經過反射識別。可是加強方法必須使用void afterThrowing([Method method, Object[] args, Object target], Throwable)這種格式的方法簽名。

(5)    引介加強

        Spring提供了org.springframework.aop.IntroductionInterceptor,表示在目標方法中添加一些新的方法和屬性,並不經常使用,因此這裏不介紹了,感興趣能夠本身查找資料

相關文章
相關標籤/搜索