aop基础使用测试记录

现象:
spring-aop基础使用测试记录

1:切入点表达式

  • execution: 通过指定包路径和方法 可匹配到方法级别
  • within:通过指定类路径 只能匹配类级别不能详细控制方法
  • target:目标对象类为指定的类型被拦截
  • args:匹配方法中的参数
  • @target:匹配调用的目标对象类有一个指定的注解
  • @within:匹配被调用的方法所属的类中是否声明了指定注解
  • @annotation:匹配被调用的方法上有指定的注解
  • @args:匹配被调用的方法参数上有指定的注解

2:五种通知

  • @Before 前置通知:在我们执行目标方法之前运行
  • @After 后置通知:在我们执行目标方法结束之后,不管有没有异常
  • @AfterReturning 返回通知:在我们的目标方法正常返回后运行
  • @AfterThrowing 异常通知:在我们的目标方法出现异常后运行
  • @Around:环绕通知:动态代理,需要手动执行jionPoint.process()可包含上面四种通知

3:JoinPoint、ProceedingJoinPoint 参数

  • getignature 获取目标方法名、参数、所属class类等信息
    • joinPoint.getSignature().getDeclaringType().getSimpleName() 获取类名
    • joinPoint.getSignature().getName() 获取方法名
  • getArgs() 获取传入方法的参数
  • getTarget() 获取被代理的对象
  • getThis() 获取代理的对象

4:jar包


    org.springframework.boot
    spring-boot-starter-aop

方法:

定义RequestController 做为拦截对象
aop基础使用测试记录_第1张图片
定义MyTestAop做aop测试
aop基础使用测试记录_第2张图片

定义自定义注解MyAnnitation 拥有两个属性 message和order
aop基础使用测试记录_第3张图片

一:使用前置通知 测试 execution表达式

1:定义controller test/a方法 返回A
aop基础使用测试记录_第4张图片
2:aop定义execution表达式
aop基础使用测试记录_第5张图片
代码:

	/**
	 * 定义切入点 : execution表达式
	 * 通过指定包路径和方法 可匹配到方法级别
	 * ..* : 这个包下全部类
	 * .*(..) : 这个类下面全部方法
	 * 可 && || ! 使用
	 */
	@Pointcut("execution(public * com.spring.aop.api..*.*(..))")
	public void pointE(){}

3:定义前置通知测试
aop基础使用测试记录_第6张图片代码:

	/**
	 * 前置通知:在我们执行目标方法之前运行
	 * 使用execution表达式
	 */
	@Before(value = "pointE()")
	public void requestBefore(JoinPoint joinPoint){
	    var args = joinPoint.getArgs();
	    var first = Arrays.stream(args).findFirst().orElse("");
	    var json = String.valueOf(first);
	    log.debug("=================前置通知执行中:{}",json);
	}

4:启动项目访问test/a
aop基础使用测试记录_第7张图片在这里插入图片描述

二:使用后置通知测试within表达式

1:定义需要拦截的controller方法 test/b

 @PostMapping("/b")
 public String getB(@RequestBody AopTestRequest request){
     log.debug("b请求执行:{}",request);
     return "B";
 }

2:aop定义within表达式

 /**
  * 定义切入点 : within表达式
  * 通过指定类路径  只能匹配类、包等级别不能详细控制方法
  * 指定拦截RequestController类
  */
 @Pointcut("within(com.spring.aop.api.RequestController)")
 public void pointW(){}

3:使用后置通知测试

/**
  * 在我们执行目标方法结束之后,不管有没有异常
  * 后置通知测试within表达式
  */
 @After(value = "pointW()")
 public void requestAfter(JoinPoint joinPoint){
     var args = joinPoint.getArgs();
     var first = Arrays.stream(args).findFirst().orElse("");
     var json = String.valueOf(first);
     log.debug("=================后置通知执行中:{}",json);
 }

4:访问test/b方法测试
aop基础使用测试记录_第8张图片

三:使用返回通知测试target表达式

1:定义需要拦截的test/c方法

    @PostMapping("/c")
    public String getC(@RequestBody AopTestRequest request){
        log.debug("c请求执行:{}",request);
        return "C";
    }

2:定义target表达式

    /**
     * 定义切入点 : target表达式
     * 目标对象为指定的类型被拦截
     * 此处拦截RequestController类型的对象
     */
    @Pointcut("target(com.spring.aop.api.RequestController)")
    public void pointT(){}

3:使用返回通知测试

    /**
     * 在我们的目标方法正常返回后运行
     * 返回通知测试target表达式
     */
    @AfterReturning(value ="pointT()" ,returning = "result")
    public void requestAfterReturning(JoinPoint joinPoint, Object result){
        var args = joinPoint.getArgs();
        var first = Arrays.stream(args).findFirst().orElse("");
        var json = String.valueOf(first);
        log.debug("=================返回通知执行中:{}",json);
        log.debug("=================返回通知执行中返回:{}",result);
    }

4:访问test/c测试
在这里插入图片描述

四:使用异常通知测试args表达式

1:定义test/d方法

   @PostMapping("/d")
    public String getD(@RequestBody AopTestRequest request){
        log.debug("d请求执行:{}",request);
        var i = 4 / 0;
        return "D";
    }

2:定义aop args表达式

    /**
     * 定义切入点 : args 表达式
     * 匹配方法中的参数
     *  args(com.spring.aop.api.request.AopTestRequest) 匹配只有一个参数且指定类型
     *  args(com.spring.aop.api.request.AopTestRequest,..) 匹配多个参数第一个指定类型
     *  args(com.spring.aop.api.request.AopTestRequest,com.spring.aop.api.request.AopTestRequest2) 匹配多个参数指定多个类型
     *  within 指定包路径只匹配自己的  防止匹配到其他包里面的final对象 导致无法代理报错
     */
    @Pointcut("args(com.spring.aop.api.request.AopTestRequest) && within(com.spring.aop..*)")
    public void pointA(){}

3:定义异常通知测试

    /**
     * 异常通知:在我们的目标方法出现异常后运行
     */
    @AfterThrowing(value = "pointA()",throwing = "e")
    public void requestAfterThrowing(JoinPoint joinPoint,Exception e){
        var args = joinPoint.getArgs();
        var first = Arrays.stream(args).findFirst().orElse("");
        var json = String.valueOf(first);
        log.debug("=================异常通知执行中:{}",json);
        log.debug("=================异常通知执行中e:{}",e.getMessage());
    }

4:访问test/d方法测试
在这里插入图片描述

五:使用环绕通知测试 @target表达式

1:定义方法test/e

    @PostMapping("/e")
    public String getE(@RequestBody AopTestRequest request){
        log.debug("e请求执行:{}",request);
        return "e";
    }

2:aop定义@target表达式

    /**
     * 定义切入点 : @target表达式
     * 匹配的目标的类有一个指定的注解
     * 这个类全部方法都拦截
     * 此处拦截有自定义注解MyAnnitation的类 
     */
    @Pointcut("@target(com.spring.aop.annotation.MyAnnitation) && within(com.spring.aop..*)")
    public void pointTA(){}

3:在controller 上使用自定义注解MyAnnitation
aop基础使用测试记录_第9张图片
4:定义环绕通知测试

    /**
     * 动态代理,需要手动执行jionPoint.process(),其实就是执行我们的目标方法执行之前,相当于前置通知,执行之后就相当于我们的后置通知
     */
    @Around("pointTA()")
    public void requestAround(ProceedingJoinPoint point){
        var methodName = point.getSignature().getName();
        try{
            // 先执行前置通知
            log.debug("=================环绕通知-前置通知:执行中:{}",methodName);

            // 执行目标方法
            var result = point.proceed();

            // 正常返回通知
            log.debug("=================环绕通知-正常返回通知:执行中:{}",result);
        }catch (Throwable e){
            log.debug("=================环绕通知-异常通知执行中:",e);
        }
        // 后置通知
        log.debug("=================环绕通知-后置通知:执行中:{}",methodName);
    }

5:访问test/e方法测试
aop基础使用测试记录_第10张图片

六:使用前置通知测试@within表达式

1:定义方法test/f

    @PostMapping("/f")
    public String getF(@RequestBody AopTestRequest2 request){
        log.debug("f请求执行:{}",request);
        return "f";
    }

2:定义aop @within表达式

    /**
     * 定义切入点 : @within表达式
     * 判断被调用的方法所属的类中是否声明了指定注解
     * 此处被调用方法所属的类是RequestController
     */
    @Pointcut("@within(com.spring.aop.annotation.MyAnnitation) && within(com.spring.aop..*)")
    public void pointWI(){}

3:定义前置通知测试

    /**
     * 前置通知:在我们执行目标方法之前运行
     *  测试@within表达式
     */
    @Before(value = "pointWI()")
    public void requestBefore(JoinPoint joinPoint){
        var args = joinPoint.getArgs();
        var first = Arrays.stream(args).findFirst().orElse("");
        var json = String.valueOf(first);
        log.debug("=================前置通知执行中:{}",json);
    }

4:被调用方法所属类 RequestController增加自定义注解
aop基础使用测试记录_第11张图片5:访问test/f方法测试
在这里插入图片描述

七:使用前置通知测试@args表达式

1:定义test/g方法 使用AopTestRequest2 入参

    @PostMapping("/g")
    public String getG(@RequestBody AopTestRequest2 request){
        log.debug("g请求执行:{}",request);
        return "g";
    }

2:定义aop表达式

    /**
     * 定义切入点 : @args表达式
     * 方法参数上有指定的注解,被匹配
     * within指定只匹配自己的路径 防止匹配到其他final的对象
     */
    @Pointcut("@args(com.spring.aop.annotation.MyAnnitation) && within(com.spring.aop..*)")
    public void pointAR(){}

3: 使用前置通知测试

    /**
     * 前置通知:在我们执行目标方法之前运行
     */
    @Before(value = "pointAR()")
    public void requestBefore(JoinPoint joinPoint){
        var args = joinPoint.getArgs();
        var first = Arrays.stream(args).findFirst().orElse("");
        var json = String.valueOf(first);

        var simpleName = joinPoint.getSignature().getDeclaringType().getSimpleName();

        log.debug("=================前置通知执行中:类名:{}",simpleName);
        log.debug("=================前置通知执行中:{}",json);
    }

4:访问的方法入参对象增加自定义注解
aop基础使用测试记录_第12张图片
5:test/g方法参数的类使自定义注解@MyAnnitation
aop基础使用测试记录_第13张图片5:方法test/g方法测试
在这里插入图片描述

八:使用前置通知测试自定义注解

1:定义方法test/h
方法上携带自定义注解@MyAnnitation

    @PostMapping("/h")
    @MyAnnitation(message = "消息",order = 100)
    public String getH(@RequestBody AopTestRequest request){
        log.debug("h请求执行:{}",request);
        return "H";
    }

2: aop定义前置通知测试@annotation

    /**
     * 前置通知:自定义注解
     */
    @Before(value = "@annotation(myAnnitation)")
    public void requestBefore(JoinPoint joinPoint,MyAnnitation myAnnitation){
        var args = joinPoint.getArgs();
        var first = Arrays.stream(args).findFirst().orElse("");
        var json = String.valueOf(first);
        log.debug("=================前置通知执行中:{}",json);

        // 1,获取自定义注解中的数据内容
        var message = myAnnitation.message();
        var order = myAnnitation.order();

        log.debug("=================前置通知执行获取自定义注解的内容-message:{}、order:{}",message,order);

    }

3:访问test/h方法
aop基础使用测试记录_第14张图片

你可能感兴趣的:(Spring,java,spring,后端)