一、切面定义
切面 = 切点+通知
-
切点(pointcut): 定义执行切面的入口点 ,这里切入点指示符
-
通知:interceptor实现切面逻辑
二、切入点指示符的含义及使用(execution、within、this、target等)
- execution:用于匹配方法执行的连接点 execution(* com.test.method.des...(..))
- execution() 表达式的主体
- 第一个“*”符号 表示返回值的类型任意
- com.test.method.des AOP所切的服务的包名,即,需要进行横切的业务类
- 包名后面的“..” 表示当前包及子包
- 第二个“” 表示类名,即所有类
- .*(..) 表示任何方法名,括号表示参数,两个点表示任何参数类型
- within:用于匹配指定类型内的方法执行,within比较严格,它是严格匹配被代理对象类型的,不会理会继承关系,例如A继承了接口B,则within("B")不会匹配到A,但是within("B+")可以匹配到A
- within(cn.java..*) . cn.java包及子包下的任何方法执行
- within(java..IPointcutService+) . java包或所有子包下IPointcutService类型及子类型的任何方法
- within(@cn..Secure *) 持有cn..Secure注解的任何类型的任何方法
- target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配 , 例如A继承了B接口,则使用target("B"),target("A")均可以匹配到A, 我们pointcut 所选取的Join point 的所有者,直白点说就是: 指明拦截的方法属于那个类。
- this:用于匹配当前AOP代理对象类型的执行方法,注意是AOP代理对象的类型匹配, 我们pointcut 所选取的Join point 的调用的所有者,就是说:方法是在那个类中被调。
三、切面应用实例
/**
* 定义日志注解
*/
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 {
/**
* 标注该方法体为后置通知,当目标方法执行成功后执行该方法体
*/
@AfterReturning("within(test..*) && @annotation(rl)")
public void addLogSuccess(JoinPoint jp, Log rl){
Object[] parames = jp.getArgs();//获取目标方法体参数
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();//获取目标类名
System.out.println("className:" + className);
className = className.substring(className.indexOf("test"));
String signature = jp.getSignature().toString();//获取目标方法签名
System.out.println("signature:" + signature);
System.out.println(rl.desc());
}
@Pointcut("@annotation(test.anotation.Log)")
public void serviceMethodPointcut() {
//切点
}
/**
* 前置通知方法, 匹配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);
}
/**
* 环绕通知, 注解切点匹配
* @param pjp
* @return
* @throws Throwable
*/
@Around("serviceMethodPointcut()")
public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
//通知方法
String className = pjp.getTarget().getClass().toString();//获取目标类名
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();
}
}
网友评论