SpringAOP使用方法—学习文档-三、切点

注意内容:

/**
 * 通配符说明:
 * .:包和包、包和方法之前的普通连接符号
 * ..:如果用在路径上,代表中间可有有多个任意路径(中间用.分隔的多个路径);如果用在方法参数上,代表不限制参数列表
 * *:指代任意单个单词,可以用在路径(包名、类名、方法名)、修饰符、返回值类型
 * +:匹配任何继承自指定的类,例如:execution(* com.example.Parent+.*(..)):匹配com.example.Parent类及其子类的任何方法。
 */

/**
 * 注意事项:
 * 1、如果在通知方法中使用JoinPoint类型参数,那就一定要放在第1个,否则会导致tomcat启动过程中出现空指针异常,从而启动失败;当然可以选择不放
 */

1、execution

// 测试:execution
// 用途:指定到方法级别
// 通配符:允许使用
// 格式:execution(修饰符 返回值类型 方法路径(参数类型列表))
// 注意:修饰符可以省略,省略代表不限制修饰符
//    @Pointcut("execution(public String com.atguigu.test.controller.TestController.test(..))") // 指定修饰符、返回值类型、方法全路径、任意参数类型
//    @Pointcut("execution(* com.atguigu.test.controller.TestController.test(..))") // 任意修饰符、任意返回值类型、方法全路径、任意参数类型
@Pointcut("execution(* com.atguigu.*.service..test(..))") // 任意修饰符、任意返回值类型、指定包下的所有方法
public void executionPointcut() {}

@Before("executionPointcut()")
public void executionAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试execution,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

2、within

// 测试:within
// 用途:指定到类级别
// 通配符:允许使用
// 格式:within(类路径)
@Pointcut("within(com.atguigu.test.controller.TestController)") // 具体类
//    @Pointcut("within(com.atguigu.test.service.impl.*)") // 包中所有类
//    @Pointcut("within(com..test..*)") // 子包中所有类(包名称以com开头,中间包含test即可)
public void withinPointcut() {}

@Before("withinPointcut()")
public void withinAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试within,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

3、this

// 测试:this
// 用途:指定接口,捕获接口实现类中方法被调用的情况
// 通配符:禁止使用
// 格式:this(接口路径)
// 注意:接口路径不允许使用通配符类型模式,必须使用类型名称
@Pointcut("this(com.atguigu.test.service.TestService)")
public void thisPointcut() {}

@Before("thisPointcut()")
public void thisAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试this,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

4、target

// 测试:target
// 用途:指定接口,捕获接口实现类中方法被调用的情况
// 通配符:禁止使用
// 格式:target(接口路径)
// 注意:接口路径不允许使用通配符类型模式,必须使用类型名称
@Pointcut("this(com.atguigu.test.service.TestService)")
public void targetPointcut() {}

@Before("targetPointcut()")
public void targetAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试target,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

5、args

// 测试:args
// 用途:指定参数类型
// 格式:args(参数类型列表)
@Pointcut("within(com.atguigu.test.controller.TestController) && args(String)")
public void argsPointcut() {}

@Before("argsPointcut()")
public void argsAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试args,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

6、@annotation

// 测试:@annotation
// 用途:指定方法上的注解,添加该注解的方法都是连接点方法
// 通配符:禁止使用
// 格式:@annotation(注解路径)
// 注意:注解路径不允许使用通配符类型模式,必须使用类型名称
@Pointcut("@annotation(com.atguigu.test.annotation.TestAnnotation)")
public void atAnnotationPointcut() {}

@Before("atAnnotationPointcut()")
public void atAnnotationAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试@annotation,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

7、@within

// 测试:@within
// 用途:指定类上的注解,添加该注解的类中所有方法都是连接点方法
// 通配符:禁止使用
// 格式:@within(注解路径)
// 注意:注解路径不允许使用通配符类型模式,必须使用类型名称
@Pointcut("@within(com.atguigu.test.annotation.TestAnnotation)")
public void atWithinPointcut() {}

@Before("atWithinPointcut()")
public void atWithinAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试@within,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

8、@target

// 测试:@target
// 警告:没搞懂怎么用,暂时放弃了

9、@args

// 测试:@args
// 用途:指定参数所属类上的注解,从而确定连接点方法
// 格式:@args(参数类型添加的注解路径)
@Pointcut("within(com.atguigu.test.service..*) && @args(com.atguigu.test.annotation.TestAnnotation, ..)")
public void atArgsPointcut() {}

@Before("atArgsPointcut()")
public void atArgsAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试@args,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

10、组合切点表达式

// 测试:组合切点(Pointcut)表达式
// 格式:支持通过 &&、||、! 来组合 pointcut 表达式
@Pointcut("executionPointcut() || atAnnotationPointcut() || atWithinPointcut()")
public void combinationPointcut() {}

@Before("combinationPointcut()")
public void combinationAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试组合切点表达式,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

11、在@Before注解中使用自定义的切入点表达式,以及切入点方法

// 说明:在@Before注解中使用切入点方法
@Before("executionPointcut() || atAnnotationPointcut() || atWithinPointcut()")
public void mix1PointcutAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试通知中使用组合切入点方法,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}


// 说明:在@Before注解中使用自定义的切入点表达式
@Before("execution(* com.atguigu.*.service..test(..)) || @annotation(com.atguigu.test.annotation.TestAnnotation)")
public void mix2PointcutAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试通知中使用组合自定义的切入点表达式,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}


// 说明:在@Before注解中使用自定义的切入点表达式 + 切入点方法
@Before("execution(* com.atguigu.*.service..test(..)) || atAnnotationPointcut() || atWithinPointcut()")
public void mix3PointcutAdvice(JoinPoint joinPoint) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试通知中使用组合 自定义的切入点表达式 + 切入点方法,目标类名称:%s、连接点(方法)名称:%s\n",  className, methodName);
}

12、获取指定类型的真实对象

@Before(value = "getObjPointcut(classAnnotation, methodAnnotation, entity, entityAnnotation)")
public void getObjAdvice(JoinPoint joinPoint, TestAnnotation classAnnotation, TestAnnotation methodAnnotation, TestEntity entity, TestAnnotation entityAnnotation) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试借助切点方法获取相应对象,目标类名称:%s、连接点(方法)名称:%s、类注解值:%s、方法注解值:%s、方法参数名称:%s、方法参数对应类注解值:%s\n",  className, methodName, classAnnotation.value(), methodAnnotation.value(), entity.getClass().getSimpleName(), entityAnnotation.value());
}

@Before(value = "@within(classAnnotation) && @annotation(methodAnnotation) && args(entity, ..) && @args(entityAnnotation, ..)")
public void getObj2Advice(JoinPoint joinPoint, TestAnnotation classAnnotation, TestAnnotation methodAnnotation, TestEntity entity, TestAnnotation entityAnnotation) {
    String className = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    System.out.printf("===测试直接获取相应对象,目标类名称:%s、连接点(方法)名称:%s、类注解值:%s、方法注解值:%s、方法参数名称:%s、方法参数对应类注解值:%s\n",  className, methodName, classAnnotation.value(), methodAnnotation.value(), entity.getClass().getSimpleName(), entityAnnotation.value());
}
上一篇:从Windows 11 23H2升级至24H2后,Git操作提示文件所有权错误的3种有效解决方案


下一篇:【LangChain】(三)如何利用LangChain和TruLens提升大规模语言模型的质量?全面教程与实战案例!