官網路徑:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans
一:術語介紹
通知(Advice)
指切面(定義為aspect的類)中的工作;
spring切面可以應用的五種通知:
前置通知(Before):在目標方法被調用之前調用通知功能;
后置通知(After):在目標方法完成之后調用通知,此時不會關心方法的輸出是什么;
返回通知(After-returning):在目標方法成功執行之后調用通知;
異常通知(After-throwing):在目標方法拋出異常后調用通知;
環繞通知(Around):通知報過了被通知的方法,在被通知的方法調用之前和調用之后執行自定義的行為。
連接點(Join point)
連接點是在應用執行過程中能夠插入切面的一個點。這個點可以是調用方法時,拋出異常時,甚至修改一個字段時。切面代碼可以利用這些點插入到應用的正常流程之中,並添加新的行為。(切點方法中配置的匹配的方法都是連接點)
切點(Pointcut)
定義通知所要織入的一個或多個連接點。
切面(Aspect)
是通知和切點的結合。
引入(Introduction)
向現有的類添加新的方法和屬性。
織入(Weaving)
織入是把切面應用到目標對象並創建新的代理對象的過程。切面在指定的連接點被織入到目標對象中。在目標對象的生命周期里有多個點可以進行織入:
編譯期:切面在目標類編譯時被織入,這種方式需要特殊的編譯器。AspectJ的織入編譯器就是以這種方式織入切面的。
類加載期:切面在目標類加載到jvm時被織入。這種方式 需要特殊的類加載器(ClassLoader),它可以在目標類被引入應用之前增強該目標類的字節碼。AspectJ5的加載時織入(load-time weaving,LTW)就支持以這種方式織入切面。
運行期:切面在應用運行的某個時刻被織入。一般情況下,在織入切面時,AOP容器會為目標對象動態的創建一個代理對象。Spring AOP就是以這種方式織入切面的。
下圖展示了這些概念是如何聯系在一起的。
下面了解一下具體的切點表達式。在spring的切面中,主要使用execution指示器來設置匹配的方法。下圖中的表達式能夠設置當sleep()方法執行時觸發的通知調用。
execution()指示器選擇ViewController的sleep()方法,方法表達式以“*”號開始,表明了不關心方法返回值的類型。然后,指定了全限定方法名和類名。對於方法參數列表,使用兩個點號(. .)表明切點要選擇任意的sleep()方法,不需要考慮入參。
使用AspectJ切點表達式來選擇ViewController的sleep方法
如果我們需要設定切點僅適用於某個包下的方法,則可以使用within()指示器來指定,不同的指示器之間使用&&(and)或||(or)連接。如下圖表達式,表示只匹配com.spring包下的ViewController的sleep()方法。
spring中還引入了bean()指示器,可以限制切點只匹配特定的bean,也可以使用!bean()來匹配除了特定bean以外的其他bean。如下:
execution(* com.spring.ViewController.sleep()) and bean ("rest")
execution(* com.spring.ViewController.sleep()) and !bean ("rest")
下面寫一個切面的demo。
首先,在com.spring下的ViewController類中添加一個sleep()方法如下:
@RequestMapping("/sleep") public String sleep(){ System.out.println("sleeping………………zzzZZZ~~~~"); return "index"; }
然后,添加切面代碼。使用注解新建一個切面SleepHelper,代碼如下。
@Component @Aspect public class SleepHelper { public SleepHelper(){ } @Pointcut("execution(* com.spring.controller.ViewController.*(..))") public void sleeppoint(){ } @Before("sleeppoint()") public void beforeSleep(){ System.out.println("馬上要睡覺咯~~~"); } @AfterReturning("sleeppoint()") public void afterSleep(){ System.out.println("睡醒咯!"); } }
當然也可以這么定義
@Before("execution(* com.spring.controller.ViewController.save(..)) && args(para1,para1)") public void test(String para1,String para1) throws Exception { params= obj; }
關於參數:
com.spring.controller.ViewController.save(..)
此處為切入到具體方法:
save(..) -- .. 表示所有參數
args(para1,para1) 此處為具體參數
public void test(String para1,String para1) --方法里面的可以拿出來在方法中使用
最后,項目是maven的項目,所以需要在pom.xml中添加切面對應的依賴jar包,並在applicationContext.xml文件中添加下圖紅框中的內容:
第一個紅框中內容作用:聲明spring的aop的命名空間;
第二個紅框中內容作用:啟用aspectj的自動代理;