spring定義一個切面是件麻煩的事情,需要實現專門的接口,還要進行一些較爲複雜的配置,有沒有較爲簡單的方法???
@AspectJ註解可以很容易定義一個切面,且不需要實現任何的接口。缺點是對JDK的版本有限制,要求是5.0以上
當然對於不足5.0的版本,可以通過Schema的配置定義切面,方便程度和@AspectJ相差無幾。
無論是基於XML配置的AOP還是基於@AspectJ註解的AOP,只是在表達方式有所不同,底層都是採用動態代理技術(JDK代理或CGLib代理)。
註解是代碼的附屬信息,它遵循一個原則:註解不能直接干擾程序代碼的運行,無論是增加或刪除註解,代碼都能正常運行。java語言解釋器會忽略這些註解,而由第三方工具對註解進行解析,從而達到間接控制程序代碼的運行,它們通過java反射機制讀取註解的信息。
Pointcut和Advice分別表切點和增強,並用Advisor將兩者整體爲切面,@AspectJ則是採用註解的方式來描述切點、增強,兩者只是表述上有所不同,本質是一樣的。
代碼示例:
切面
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class PreGreetingAspect{
@Before("execution(* greetTo(..))")
public void beforeGreeting(){
System.out.println("How are you");
}
}
a. PreGreetingAspect類定義處,標註了@Aspect註解,表示其爲一個切面。
b. beforeGreeting方法上,Before表示是前置增強;execution(* greetTo(..))表示一個切點表達式,在目標類的greetTo()方法上織入增強,greetTo方法可以帶任意入參和任意返回值。
c. beforeGreeting方法體,表示具體的橫切邏輯。
PreGreetingAspect類通過註解和代碼,將切點、增強類型、增強邏輯糅合到一個類中。
配置文件
<aop:aspectj-autoproxy/>
//目標bean
<bean id="waiter" class="com.baobaotao.NaiveWaiter" />
//採用@AspectJ註解的切面類
<bean class="com.aspectj.example.PreGreetingAspect" />
//自動代理創建器,自動將@AspectJ切面類織入到目標Bean中
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
AspectJ的切點表達式由關鍵字和操作參數組成。如execution(* greetTo(..))
execution爲關鍵字(ps:表示目標類執行某一方法)
* greetTo(..)爲操作參數(ps:表示目標方法的匹配模式串)
目前spring支持9個@AspectJ切點表達式函數,他們用不同的方式描述目標類的連接點,大致分爲4種類型:
1)方法切點函數:通過描述目標類方法信息定義連接點,如execution
2)方法入參切點函數:通過描述目標類方法入參的信息定義連接點
3)目標類切點函數:通過描述目標類類型信息定義連接點
4)代理類切點函數:通過描述目標類的代理類的信息定義連接點
增強類型:
@Before 前置增強
@AfterReturning 後置增強
@Around 環繞增強
@AfterThrowing 拋出異常的增強
@DeclareParents 引介增強
與xml形式的基本一致,只是換了種表達方式,採用了註解的形式來描述。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
對於不滿足JDK5.0的項目,只能望@AspectJ而興嘆了。沒關係,我們還可以用Schema配置切面
說白了,其實就是將註解信息移到了Schema的XML配置文件中,形式不同罷了。
簡單實例:
xml配置文件
<aop:config proxy-target-class="true">
//增強方法所在的bean
<aop:aspect ref="adviceMethods">
//前置增強
<aop:before method="preGreeting"
//切點表達式,與@AspectJ的語法相同
pointcut="target(com.baobaotao.NaiveWaiter) and args(name)"
arg-names="name" />
//後置增強
<aop:after-returning method="afterReturning"
pointcut="target(com.baobaotao.SmartSeller)" returning="retVal" />
</aop:aspect>
</aop:config>
<bean id="adviceMethods" class="com.baobaotao.schema.AdviceMethods" />
<bean id="naiveWaiter" class="com.baobaotao.NaiveWaiter" />
<bean id="naughtyWaiter" class="com.baobaotao.NaughtyWaiter" />
<bean id="seller" class="com.baobaotao.SmartSeller" />
其中
1、 <aop:aspect>元素定義切面,內部可以定義多個增強
2、 <aop:config>擁有一個proxy-target-class屬性,true時表示聲明的切面採用CGLib動態代理技術;反之表示使用JDK動態代理技術
public class AdviceMethods {
public void preGreeting(String name) {
System.out.println("--how are you!--");
System.out.println(name);
}
//後置增強對應方法
public void afterReturning(int retVal){
System.out.println("----afterReturning()----");
System.out.println("returnValue:"+retVal);
System.out.println("----afterReturning()----");
}
}