前面提到了,一個切面由一個PointCut和一個Advice組成,Advice主要包含了橫切代碼以及,織入位置的部分信息(即織入PointCut給定方法的方法的前面、後面、前面和後面、異常拋出時、添加一些新的方法和屬性)。java
針對上面的位置信息,Spring提供了5種對應的子接口:前置加強、後置加強、環繞加強、異常拋出加強、引介加強。spring
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代理
Spring提供了org.springframework.aop.AfterReturningAdvice目標方法執行後實施加強
實現AfterReturningAdvice接口,實現afterReturning(Object returnObj, Method method, Object[] args, Object obj) throws Throwable方法,returnObj是方法返回結果,其餘與前置加強同樣。
還有一點與前置加強區別,當發生異常時,若是異常是目標方法聲明的異常,異常將歸併到目標方法,不然將異常轉換成運行期異常拋出。
因爲後置加強與前置用法相識,這裏就不寫例子了
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; } }
Spring提供了org.springframework.aop.ThrowsAdvice表示在目標方法拋出異常後實施加強
異常拋出加強最適合是事物的回滾操做,在ThrowsAdvice接口中並無定義任何的抽象方法,他只是一個標識接口,在運行期間Spring會經過反射識別。可是加強方法必須使用void afterThrowing([Method method, Object[] args, Object target], Throwable)這種格式的方法簽名。
Spring提供了org.springframework.aop.IntroductionInterceptor,表示在目標方法中添加一些新的方法和屬性,並不經常使用,因此這裏不介紹了,感興趣能夠本身查找資料