Advice的幾種定義方式
Before Advice
在切點(diǎn)方法執(zhí)行之前肆汹。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
Advice支持in-place pointcut expression,直接將PointCut的表達(dá)式寫(xiě)在Advice注解里:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
After Returning Advice
在切點(diǎn)方法正常返回后執(zhí)行笆环。注意:一定是正常返回后。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
支持綁定切點(diǎn)方法的返回值,returning后變量名需要跟doAccessCheck中的參數(shù)名保持一致闪萄,同時(shí)烈拒,retVal的類型還用來(lái)限制過(guò)濾切點(diǎn)的條件,切點(diǎn)處的方法必須匹配相應(yīng)的返回值才算符合條件:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
}
After Throwing Advice
在切點(diǎn)方法拋出異常之后執(zhí)行祖秒。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {
// ...
}
}
支持綁定異常到參數(shù)。異常可以是具體異常,用來(lái)作為切點(diǎn)過(guò)濾條件脖阵。throwing后面的參數(shù)名稱需要跟doRecoveryActions的參數(shù)名稱一致。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
}
After (Finally) Advice
跟java的finally的意義一樣搜立,不管切點(diǎn)處的方法正常返回還是拋出異常,都一定會(huì)在之后執(zhí)行的邏輯。適合用于釋放資源等顿锰。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock() {
// ...
}
}
Around Advice
在切點(diǎn)方法執(zhí)行之前和之后執(zhí)行工作谨垃,并確定方法何時(shí)、如何、甚至是否真正執(zhí)行牢撼。
Always use the least powerful form of advice that meets your requirements (that is, do not use around advice if before advice would do).
Around advice is often used if you need to share state before and after a method execution in a thread-safe manner (starting and stopping a timer, for example)
@Around注釋的方法通過(guò)ProceedingJoinPoint pjp參數(shù)來(lái)執(zhí)行被代理的切點(diǎn)方法。pjp.proceed()執(zhí)行的就是切點(diǎn)方法,pjp.proceed()還有個(gè)重載方法是pjp.proceed(Object[] objects)胳喷,可以通過(guò)使用后面的重載方法給切點(diǎn)方法傳入?yún)?shù)尊惰,傳入的參數(shù)會(huì)覆蓋掉原參數(shù)(注意讲竿,這里傳遞的參數(shù)使用Full AspectJ和Spring AOP的語(yǔ)義是不同的泥兰,不過(guò)可以通過(guò)后面講解綁定參數(shù)的方式做到兼容)。doBasicProfiling的返回值最終作為切點(diǎn)方法的返回值返回迈嘹。所以削彬,通過(guò)@Around注解是有能力篡改切點(diǎn)方法的輸入?yún)?shù)和返回值的。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}
總之秀仲,因?yàn)榍悬c(diǎn)方法是通過(guò)ProceedingJoinPoint參數(shù)調(diào)用的融痛,所以@Around可以完全控制切點(diǎn)方法的訪問(wèn),甚至可以在某些條件滿足的情況下不調(diào)用切點(diǎn)方法也是完全支持的神僵。
Advice Parameters
Access to the Current JoinPoint
所有的Advice方法都可以通過(guò)傳入org.aspectj.lang.JoinPoint參數(shù)來(lái)通過(guò)以下方法訪問(wèn)切點(diǎn)的具體信息(@Around必須傳入ProceedingJoinPoint雁刷,ProceedingJoinPoint是JoinPoint子類):
- getArgs(): Returns the method arguments.
- getThis(): Returns the proxy object.
- getTarget(): Returns the target object.
- getSignature(): Returns a description of the method that is being advised.
- toString(): Prints a useful description of the method being advised.
Passing Parameters to Advice
在前面已經(jīng)講解了如何綁定返回值和異常對(duì)象。下面的實(shí)例給出如何綁定切點(diǎn)方法的參數(shù)挑豌,將參數(shù)傳遞給Advice方法:
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")
public void validateAccount(Account account) {
// ...
}
args(account,..)在這里有兩個(gè)用途安券。第一墩崩,限制匹配到的切點(diǎn)方法至少包含一個(gè)參數(shù)氓英,并且參數(shù)類型為Account;第二鹦筹,切點(diǎn)方法的Account參數(shù)對(duì)象可以傳遞給validateAccount使用铝阐。
與上面等價(jià)的定義方式如下:
@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")
private void accountDataAccessOperation(Account account) {}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ...
}
this,target铐拐,annotations (@within, @target, @annotation, and @args)也可以用來(lái)綁定參數(shù)徘键。
The proxy object ( this), target object ( target), and annotations ( @within, @target, @annotation, and @args) can all be bound in a similar fashion.
定義Auditable注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {
AuditCode value();
}
示例中,用來(lái)匹配使用Auditable注解的公共方法作為切點(diǎn)遍蟋,同時(shí)將注解綁定至參數(shù)吹害。
@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
public void audit(Auditable auditable) {
AuditCode code = auditable.value();
// ...
}
Advice Parameters and Generics
Spring AOP支持泛型類和泛型參數(shù)的方法。
假設(shè)有以下接口:
public interface Sample<T> {
void sampleGenericMethod(T param);
void sampleGenericCollectionMethod(Collection<T> param);
}
以下示例用來(lái)匹配上面Sample<T>接口中定義的泛型方法和綁定泛型參數(shù):
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param) {
// Advice implementation
}
但是對(duì)于集合來(lái)說(shuō)虚青,以下的切點(diǎn)定義是不允許的:
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
public void beforeSampleMethod(Collection<MyType> param) {
// Advice implementation
}
如果非要使用集合它呀,那么可以定義Collection<?>,由用戶自己來(lái)針對(duì)集合中的類型進(jìn)行檢查和轉(zhuǎn)換棒厘。
Proceeding with Arguments
@Around("execution(List<Account> find*(..)) && " +
"com.xyz.myapp.SystemArchitecture.inDataAccessLayer() && " +
"args(accountHolderNamePattern)")
public Object preProcessQueryPattern(ProceedingJoinPoint pjp,
String accountHolderNamePattern) throws Throwable {
String newPattern = preProcess(accountHolderNamePattern);
return pjp.proceed(new Object[] {newPattern});
}
Advice Ordering
多個(gè)Advice的優(yōu)先級(jí)設(shè)置以及需要注意的地方纵穿。
This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation. Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.
When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefined