Spring中切點表達式的重用

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

微博地址: http://weibo.com/luoyepiaoxue2014 點擊打開鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章