Aop之自定义注解用法与用途-切点与切面

本文介绍了如何在Spring Boot中使用AspectJ自定义注解实现前置后置通知,并演示了如何通过自定义注解实现接口调用的耗时监测。通过实例展示了切点定义、切面配置及其实现方法的顺序执行和时间记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Aop之自定义注解使用与介绍


切面注解说明

AspectJ 切面注解中五种通知注解:

  1. @Before: 前置通知, 在方法执行之前执行
  2. @After: 后置通知, 在方法执行之后执行
  3. @AfterRunning: 返回通知, 在方法返回结果之后执行
  4. @AfterThrowing: 异常通知, 在方法抛出异常之后
  5. @Around: 环绕通知, 围绕着方法执行

环绕通知=前置通知+目标方法执行+后置通知

下面以2个小demo说明,以springboot工程为基础

  1. 案例一:简单使用前置后置通知-顺序问题
  2. 案例二:自定义注解,记录接口调用的耗时时间
  3. 当然也有校验是否重复提交登入权限校验等拓展使用…

案例结构总览
在这里插入图片描述


一、简单使用前置后置通知

准备3个后置 由下到上执行

1、导入依赖

 <!--aop依赖-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>

2、自定义注解-切点

自定义@Recording注解

package sqy.aop_test.annotation;
import java.lang.annotation.*;

/**
 * @author suqinyi
 * @Date 2021/7/7
 */

@Documented  //用于标明该注解将会被包含在javadoc中
@Retention(RetentionPolicy.RUNTIME) //用于标明注解的生命周期
@Target({ElementType.METHOD}) //用于标明注解的作用范围
public @interface Recording {
}

3、有了切点搞个切面

注意:切面里面指定切点的2种写法

package sqy.aop_test.aspect;

import org.springframework.stereotype.Component;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * @author suqinyi
 * @Date 2021/7/7
 */
@Component
@Aspect
public class ExecuteScriptAspect {

    /**
     * AspectJ 切面注解中五种通知注解:
     *  @Before: 前置通知, 在方法执行之前执行
     *  @After: 后置通知, 在方法执行之后执行 。
     *  @AfterRunning: 返回通知, 在方法返回结果之后执行
     *  @AfterThrowing: 异常通知, 在方法抛出异常之后
     *  @Around: 环绕通知, 围绕着方法执行
     */


    /**
     * 切点 2种写法
     */
    // @Pointcut("execution(* sqy.aop_test.service.impl.AppiumServiceImpl.executeScript(..))")
    @Pointcut("@annotation(sqy.aop_test.annotation.Recording)")//自定义注解位置
    public void executeScript() {
    }

    /**
     * 前置通知最先执行
     */
    @Before("executeScript()")
    public void startRecording() {
        System.out.println("前置通知,准备搞事情,准备一些工作==>洗锅");
    }

    //---------------3个后置 由下到上《顺序》执行 ---------------

    /**
     * 后置通知, 在方法执行之后执行
     */
    @After("executeScript()")
    public void endRecording() {
        System.out.println("后置通知01==>下油");
    }

    /**
     * 后置通知, 在方法执行之后执行
     */
    @After("executeScript()")
    public void pushFile() throws InterruptedException {
        Thread.sleep(2000);//休眠2秒
        System.out.println("后置通知02====>炒菜2秒");
    }

    /**
     * 后置通知, 在方法执行之后执行
     */
    @After("executeScript()")
    public void pushFile1() {
        System.out.println("后置通知03====>出锅");
    }

}

4、搞个方法测试-注意打印顺序

package sqy.aop_test.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sqy.aop_test.annotation.Recording;
import sqy.aop_test.service.AppiumService;
/**
 * @author suqinyi
 * @Date 2021/7/7
 */
@RestController
public class RecorderController {

    @Autowired
    private AppiumService appiumService;

    /**
     * http://localhost:8080/aoptest
     */
    @Recording //自定义注解-也就是切点
    @RequestMapping("/aoptest")
    public String executeScript() {
        //appiumService.executeScript();//业务处理
        System.out.println("执行业务了...");
        return "execute ok";
    }
}

5、结果

后置通知 由下到上顺序执行
在这里插入图片描述

二、自定义耗时监测注解

1、自定义注解-切点

package sqy.aop_test.annotation;

import java.lang.annotation.*;

/**
 * @author suqinyi
 * @Date 2021/12/27
 * 自定义注解-运行时长
 */

@Documented  //用于标明该注解将会被包含在javadoc中
@Retention(RetentionPolicy.RUNTIME) //用于标明注解的生命周期
@Target({ElementType.METHOD}) //用于标明注解的作用范围
public @interface RunTime {

}

2、创建切面-环绕通知

环绕通知=前置通知+目标方法执行+后置通知

package sqy.aop_test.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @author suqinyi
 * @Date 2021/12/27
 * 运行时长的切面
 */
@Component
@Aspect
public class RunTimeAspect {

    //定义一个切点。指向我们的注解类
    @Pointcut(value = "@annotation(sqy.aop_test.annotation.RunTime)")
    public void RunTime(){
    }

    // 使用@Around环绕通知, 环绕通知=前置通知+目标方法执行+后置通知
    @Around("RunTime()")
    public Object  doAround(ProceedingJoinPoint joinPoint) { //ProceedingJoinPoint可以获取当前方法和参数等信息
        Object obj = null;
        try {
            long beginTime = System.currentTimeMillis();
            obj = joinPoint.proceed();
            //获取方法名称
            String methodName = joinPoint.getSignature().getName();
            //获取类名称
            String className = joinPoint.getSignature().getDeclaringTypeName();
            System.out.println("方法:"+methodName+"  耗时时间:"+ (System.currentTimeMillis() - beginTime) + "毫秒");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return obj;
    }

}

3、方法测试

package sqy.aop_test.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sqy.aop_test.annotation.RunTime;

/**
 * @author suqinyi
 * @Date 2021/12/27
 * 运行时长的controller
 */
@RestController
public class RunTimeController {

    // http://localhost:8080/testRunTime
    @RunTime//自定义注解-记录运行时长
    @RequestMapping("/testRunTime")
    public void testRunTime() throws InterruptedException {
        System.out.println("开始时间"+System.currentTimeMillis());
        Thread.sleep(Long.parseLong("2000"));//模拟业务时长2秒
        System.out.println("结束时间"+System.currentTimeMillis());
    }
}

4、结果

在这里插入图片描述

总结

这就是aop的简单使用了。
当然注解也能用反射的机制+拦截器+过滤器来处理一些问题。
(反射+注解)的可以参考小编的这篇博文=>自定义权限校验注解(反射+注解)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

suqinyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值