Aop之自定义注解使用与介绍
文章目录
切面注解说明
AspectJ 切面注解中五种通知注解:
- @Before: 前置通知, 在方法执行之前执行
- @After: 后置通知, 在方法执行之后执行
- @AfterRunning: 返回通知, 在方法返回结果之后执行
- @AfterThrowing: 异常通知, 在方法抛出异常之后
- @Around: 环绕通知, 围绕着方法执行
环绕通知=前置通知+目标方法执行+后置通知
下面以2个小demo说明,以springboot工程为基础
- 案例一:简单使用前置后置通知-顺序问题
- 案例二:自定义注解,记录接口调用的耗时时间
- 当然也有
校验是否重复提交
、登入权限校验
等拓展使用…
案例结构总览
一、简单使用前置后置通知
准备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的简单使用了。
当然注解也能用反射的机制+拦截器+过滤器来处理一些问题。
(反射+注解)的可以参考小编的这篇博文=>自定义权限校验注解(反射+注解)