AspectJ中切入点表达式
- 语法:@Before(value =“execution(权限修饰符 返回值类型 包名.类名.方法名(参数类型))”)
- 通配符
- [*]:
- 可以代表 任意权限修饰符&返回值类型
- 可以代表任意的包名、任意的类名、任意的方法名
- […]:
- 代表任意的参数类型以及参数个数
- [*]:
- 重用切入点表达式
- 使用@PointCut注解,提取可重用的切入点表达式
- 使用方法名()引入切入点表达式
@Component
@Aspect //标注为切面类
public class MyLogging {
//重用切入点表达式
@Pointcut(value = "execution(* com.zyh.aop.CalcImpl.*(..))")
public void myPointCut() {
}
@Before(value = "myPointCut()")
public void beforeMethod(JoinPoint joinPoint) {
//方法名称
String name = joinPoint.getSignature().getName();
//获取参数
Object[] args = joinPoint.getArgs();
System.out.println("==>Calc中" + name + "方法(),参数:" + Arrays.toString(args));
}
@After(value = "myPointCut()")
public void afterMethod() {
// System.out.println("==>Calc中"+methodName+"方法(),结果:"+ res);
System.out.println("==>Calc方法之后执行");
}
}
AspectJ中JoinPoint
- JopinPoint[切入点对象]
- 作用:
- 获取方法名称
String name = joinPoint.getSignature().getName();
joinPoint.getSignature()
获取方法签名[方法名拼接上参数列表]
- 获取参数
Object[] args = joinPoint.getArgs();
- 获取方法名称
AspectJ中通知
- 前置通知
- 语法:@Before
- 执行时机:在指定方法执行之前[如目标方法中有异常,会执行]
- 指定方法:切入点表达式设置位置
@Before(value = "myPointCut()")
public void beforeMethod(JoinPoint joinPoint) {
//方法名称
String name = joinPoint.getSignature().getName();
//获取参数
Object[] args = joinPoint.getArgs();
System.out.println("==>Calc中" + name + "方法(),参数:" + Arrays.toString(args));
}
-
后置通知
- 语法:@After
- 执行时机:在指定方法执行之后执行[如目标方法中有异常,会执行]
- 示例代码
@After(value = "myPointCut()")
public void afterMethod(JoinPoint joinPoint) {
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("==>Calc中"+name+"方法之后执行!"+Arrays.toString(args));
}
- 返回通知
- 语法:@AfterReturning
- 执行时机:指定方法返回结果时执行 [如果目标方法有异常则不执行]
- 注意:@AfterReturning中returning属性与入参中参数名一致
- 代码
@AfterReturning(value = "myPointCut()",returning = "res")
public void afterReturning(JoinPoint joinPoint,Object res){
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("[返回通知]==>Calc中"+name+"返回结果执行!结果"+res);
}
- 异常通知
- 语法:使用@AfterThrowing注解标识
- 执行时机:指定方法出现异常时执行[如果目标方法没有异常,不执行]
- 在异常通知中,通过@AfterThrowing注解的throwing属性获取异常信息。Throwable是所有错误和异常的顶级父类,所以在异常通知方法可以捕获到任何错误和异常
- 如果只是对某种特殊的异常类型感兴趣,可以把参数声明为其他异常的参数类型,然后通知就只在抛出这个类型及其子类的异常时才被执行
- 注意事项:@AfterThrowing中的throwing属性值与参数名一致
- 实现
- 环绕通知[前四个通知整合]
- 语法:@Around
- 作用:整合前四个通知
- 注意:参数中必须使用ProceedingJoinPoint,环绕通知一定要有返回值
@Around(value = "myPointCut()")
public Object aroundMethod(ProceedingJoinPoint joinPoint) {
// //方法名称
String name = joinPoint.getSignature().getName();
//获取参数
Object[] args = joinPoint.getArgs();
Object rs = null;
try {
//前置通知 后置通知[有异常执行] 返回通知[有异常不执行] 异常通知
System.out.println("[前置通知]==>Calc中" + name + "方法(),参数:" + Arrays.toString(args));
//触发目标对象的目标方法[对应的加减乘除]
rs = joinPoint.proceed();
//返回通知
System.out.println("[返回通知]==>Calc中" + name + "返回结果执行!结果" + rs);
} catch (Throwable e) {
e.printStackTrace();
//异常通知
System.out.println("[异常通知]==>Calc中" + name + "方法,出现异常时执行!异常是:" + e);
} finally {
//后置通知[有异常执行]
System.out.println("[后置通知]==>Calc中" + name + "方法之后执行!" + Arrays.toString(args));
}
return rs;
}
切面的优先级
数据可能还需要验证等 ,就涉及到切面优先级问题
- 语法:@Ordder(value=index)
- index是int类型,默认值是int可存储的最大值
- 数值最小,优先级越高
/**添加数据的验证功能
* @author zengyihong
* @create 2022--07--03 10:11
*/
@Component
@Aspect
@Order(value = 1)
public class MyValidate {
/**
* 添加数据的验证功能
*/
@Before(value = "com.zyh.aop.MyLogging.myPointCut()")
public void before(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("-----数据验证的切面----------");
}
}