Spring中切點表達式的重用
一、說在前面
從上面幾篇文章的學習中,我們可以看到在對應通知的表單時總要指定execution(* *.*(..)),修改起來需要多次修改重複的地方,很麻煩。爲了方便修改我們引入了@PointCut。二、引入@Pointcut之後的代碼
爲了便於對比,在代碼中只是將 未引用@Pointcut之前的代碼註釋掉。ArithmeticCalculator接口及對應的實現類、applicationContext.xml配置文件、測試函數都和上篇文章中一模一樣,在這裏就不在贅述。
下面直接展示重用部分代碼LoggingAspect類:
package com.at.aop;
import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
/*
* 切點表達式的重用:
* 定義一個方法,用於聲明切入點表達式;一般情況下,改方法中不需要添加其他的代碼。
* 使用 @Pointcut 來聲明切入點表達式
* 後面的其他通知直接使用方法名來引入當前的切入點表達式
*/
@Pointcut("execution(* com.at.aop.ArithmeticCalculator.*(..))")
public void declareJoinPointExpression(){
}
//前置通知:在com.at.aop.ArithmeticCalculator 接口的實現類的每一個方法開始之前執行一段代碼
//@Before("execution(public int com.at.aop.ArithmeticCalculator.*(..))")
@Before("declareJoinPointExpression()")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("前置通知方法 "+methodName+" 開始 "+args);
}
//後置通知:在目標方法執行後(無論是否發生異常),執行的通知。
//在後置通知中還不能訪問目標方法執行的結果。這個結果需要在返回通知中訪問(下文講)
//@After("execution(* com.at.aop.ArithmeticCalculator.*(..))")
@After("declareJoinPointExpression()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("後置通知方法 "+methodName+" 結束 ");
}
//返回通知:在代碼正常執行之後返回的代碼
//返回通知是可以訪問到方法的返回值的。
//@AfterReturning(value="execution(* com.at.aop.ArithmeticCalculator.*(..))",returning="result")
@AfterReturning(value="declareJoinPointExpression()",returning="result")
public void afterReturning(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("返回通知方法 "+methodName+" 結果爲 "+result);
}
//異常通知
//@AfterThrowing(value="execution(* com.at.aop.ArithmeticCalculator.*(..))",throwing="ex")
@AfterThrowing(value="declareJoinPointExpression()",throwing="ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("異常通知方法 "+methodName+" 發生的異常爲 "+ex);
}
/*環繞通知需要攜帶 ProceedingJoinPoint 類型的參數
* 環繞通知類似於動態代理的全過程: ProceedingJoinPoint 類型的參數可以決定是夠執行目標方法
* 並且環繞通知必須有返回值,返回值就是目標方法的返回值。
*/
//@Around("execution(* com.at.aop.ArithmeticCalculator.*(..))")
@Around("declareJoinPointExpression()")
public Object aroundMethod(ProceedingJoinPoint pjp){
Object result = null;
String methodName = pjp.getSignature().getName();
try {
//前置通知
System.out.println("環繞通知中的前置通知方法 "+methodName+" 開始於參數 "+Arrays.asList(pjp.getArgs()));
//執行目標
result = pjp.proceed();
//返回通知
System.out.println("環繞通知中的返回通知方法 "+methodName+" 結果爲 "+result);
} catch (Throwable e) {
//異常通知
System.out.println("環繞通知中的異常通知方法 "+methodName+" 結果爲 "+e);
throw new RuntimeException(e);
}
//後置通知
System.out.println("環繞通知中的後置通知方法 "+methodName+" 結束了 ");
return result;
}
}
By luoyepiaoxue2014