一芭逝、切面定義
切面 = 切點(diǎn)+通知
切點(diǎn)(pointcut): 定義執(zhí)行切面的入口點(diǎn) ,這里切入點(diǎn)指示符
通知:interceptor實(shí)現(xiàn)切面邏輯
二巍棱、切入點(diǎn)指示符的含義及使用(execution遗契、within、this行剂、target等)
- execution:用于匹配方法執(zhí)行的連接點(diǎn) execution(* com.test.method.des...(..))
- execution() 表達(dá)式的主體
- 第一個(gè)“*”符號(hào) 表示返回值的類型任意
- com.test.method.des AOP所切的服務(wù)的包名秕噪,即,需要進(jìn)行橫切的業(yè)務(wù)類
- 包名后面的“..” 表示當(dāng)前包及子包
- 第二個(gè)“” 表示類名厚宰,即所有類
- .*(..) 表示任何方法名腌巾,括號(hào)表示參數(shù),兩個(gè)點(diǎn)表示任何參數(shù)類型
- within:用于匹配指定類型內(nèi)的方法執(zhí)行,within比較嚴(yán)格铲觉,它是嚴(yán)格匹配被代理對(duì)象類型的澈蝙,不會(huì)理會(huì)繼承關(guān)系,例如A繼承了接口B撵幽,則within("B")不會(huì)匹配到A灯荧,但是within("B+")可以匹配到A
- within(cn.java..*) . cn.java包及子包下的任何方法執(zhí)行
- within(java..IPointcutService+) . java包或所有子包下IPointcutService類型及子類型的任何方法
- within(@cn..Secure *) 持有cn..Secure注解的任何類型的任何方法
- target:用于匹配當(dāng)前目標(biāo)對(duì)象類型的執(zhí)行方法;注意是目標(biāo)對(duì)象的類型匹配 盐杂, 例如A繼承了B接口逗载,則使用target("B"),target("A")均可以匹配到A链烈, 我們pointcut 所選取的Join point 的所有者厉斟,直白點(diǎn)說就是: 指明攔截的方法屬于那個(gè)類。
- this:用于匹配當(dāng)前AOP代理對(duì)象類型的執(zhí)行方法测垛,注意是AOP代理對(duì)象的類型匹配捏膨, 我們pointcut 所選取的Join point 的調(diào)用的所有者,就是說:方法是在那個(gè)類中被調(diào)食侮。
三号涯、切面應(yīng)用實(shí)例
/**
* 定義日志注解
*/
package test.anotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Log {
String desc() default "打印日志";
}
/**
* 定義日志切面
*/
package test.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import test.anotation.Log;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
@Aspect
@Component
public class LogAspect {
/**
* 標(biāo)注該方法體為后置通知,當(dāng)目標(biāo)方法執(zhí)行成功后執(zhí)行該方法體
*/
@AfterReturning("within(test..*) && @annotation(rl)")
public void addLogSuccess(JoinPoint jp, Log rl){
Object[] parames = jp.getArgs();//獲取目標(biāo)方法體參數(shù)
for (int i = 0; i < parames.length; i++) {
System.out.println(parames[i]);
}
System.out.println(jp.getSignature().getName());
String className = jp.getTarget().getClass().toString();//獲取目標(biāo)類名
System.out.println("className:" + className);
className = className.substring(className.indexOf("test"));
String signature = jp.getSignature().toString();//獲取目標(biāo)方法簽名
System.out.println("signature:" + signature);
System.out.println(rl.desc());
}
@Pointcut("@annotation(test.anotation.Log)")
public void serviceMethodPointcut() {
//切點(diǎn)
}
/**
* 前置通知方法, 匹配test包下所有類的方法
* 方法的返回值 和 test包下所有的類和方法锯七,以及方法的形參 都抽象了
* @param point
* @return
* @throws Throwable
*/
@Before("execution(* test..*(..))")
public void beforeAdvice(JoinPoint point){
String methodName = point.getSignature().getName();
List<Object> args = Arrays.asList(point.getArgs());
System.out.println("@Before 前置通知 : 方法名 【 " + methodName + " 】and args are " + args);
}
/**
* 環(huán)繞通知链快, 注解切點(diǎn)匹配
* @param pjp
* @return
* @throws Throwable
*/
@Around("serviceMethodPointcut()")
public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
//通知方法
String className = pjp.getTarget().getClass().toString();//獲取目標(biāo)類名
System.out.println("className:" + className);
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
String methodName = method.getName();
System.out.println("methodName:" + methodName);
return pjp.proceed();
}
}