可以在手机建网站的,南昌市建设监督网站站长,网页设计与制作报告模板,图片制作用什么软件1. 快速入手
AOP#xff1a;就是面相切面编程#xff0c;切面指的就是某一类特定的问题#xff0c;也可以理解为面相特定方法编程#xff0c;例如之前使用的拦截器#xff0c;就是 AOP 思想的一种应用#xff0c;统一数据返回格式和统一异常处理也是 AOP 思想的实现方式…1. 快速入手
AOP就是面相切面编程切面指的就是某一类特定的问题也可以理解为面相特定方法编程例如之前使用的拦截器就是 AOP 思想的一种应用统一数据返回格式和统一异常处理也是 AOP 思想的实现方式
比如说需要统计每个方法执行的耗时如果正常来写的话需要在方法的开头和结尾来定义时间戳相减 如果有很多方法都需要计算的话总不能每个方法都写这些重复的代码吧接下来看通过使用 AOP 思想是如何实现的
首先需要添加对应的依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId
/dependency
然后需要添加Component注解 Slf4j
Aspect
Component
public class TimeRecordAspect {Around(execution(* com.example.springbook.controller.*.*(..)))public Object timeRecord(ProceedingJoinPoint pjt){//记录开始时间long start System.currentTimeMillis();//执行目标方法Object o null;try {o pjt.proceed();} catch (Throwable e){throw new RuntimeException(e);}log.info(pjt.getSignature() 执行耗时 (System.currentTimeMillis() - start));return o;}
}
再去调用接口的话就会计算出来对应方法消耗的时间 来简单分析一下上面的代码 2. 通知类型
Spring AOP 的通知类型有以下几种
・Around环绕通知在目标方法前、后都被执行。 ・Before前置通知在目标方法前被执行。 ・After后置通知在目标方法后被执行无论是否有异常都会执行。 ・AfterReturning返回后通知在目标方法后被执行有异常不会执行。 ・AfterThrowing异常后通知发生异常后执行。
接下来同时测试一下这些通知类型 来看一下接口正常返回的情况下的执行顺序 再来看接口发生异常的情况下的执行顺序 从上面的结果上就可以看出Around 可以完成其他类型的功能
需要注意的是
Around 环绕通知需要调用 ProceedingJoinPoint.proceed () 来让原始方法执行其他通知不需要考虑目标方法执行。Around 环绕通知方法的返回值必须指定为 Object来接收原始方法的返回值否则原始方法执行完毕是获取不到返回值的。 3. Pointcut
在上面的代码中还存在一个问题每次写一个方法都需要写一个切点表达式如果说更换切点的话那么所有的切点表达式都要修改一下就可以通过Pointcut 注解把公共的切点表达式提取出来需要用到时引用该切点表达式即可 这样提取出来其他方法想要调用直接写上方法名称即可和定义的常量类似那么同一个类下可以直接调用如果是不同的类的话需要把全限定名写上并写明是 xx 类的 xx 方法
Around(com.example.springaop.aspect.AspectDemo.pt())
执行之后也是生效了 但是如果定义时设置为了 private 的话其他类就不能执行了
Pointcut(execution(* com.example.springaop.controller.*.*(..)))
private void pt(){}
4. 切面优先级
当在一个项目中定义了多个切面类时并且这些切面类的多个切入点都匹配到了同一个目标方法那么目标方法执行的时候这些切面类中的通知方法都会执行那么这时就会有一个优先级哪个切面类先执行 通过测试发现执行的顺序也是类似于一个切面的 关于切面类的执行顺序默认是按照类名的字典序来执行的 可以Order注解通过来修改优先级 这样 AspectDemo2 的优先级就变为最高的了就先执行也就是数字越大优先级越高
5. 切点表达式
5.1. execution 表达式 访问修饰符和异常可以省略
* 表示通配符匹配任意字符不过只能匹配一个元素即只能匹配任意一种返回类型包名类名方法或者方法参数一层包使用一个 * . . 表示匹配多个连续的任意符号可以通配任意层级的包或者任意类型任意个数的参数使用 .. 配置包名表示此包以及此包下的所有子包
来看具体示例 表示匹配 TestController 下的 public 修饰返回类型为 String 方法名为 t1无参方法 如果省略访问修饰符表示匹配 public 修饰或者 protected 修饰的方法 表示匹配所有返回类型 如果再把方法名设为 * 表示所有方法上面就是匹配该类下的所有无参方法 如果设为 .. 就表示所有方法无论有参还是无参都能匹配 表示 controller 包下的所有类的所有方法都匹配 表示 com 下类名为 TestController 的所有方法 表示 demo 下的所有包的所有类的所有方法
5.2. annotation
使用 execution 表达式匹配的方法都是具有一定规律的比如 xx 包的 xx 类的 xx 方法那么如果没有规律可循的话就需要使用 annotation 注解了
首先可以通过自定义注解的方式自定义注解的创建需要选择 Annotation Retention(RetentionPolicy.RUNTIME) //注解的有效阶段
Target({ElementType.METHOD}) //表示方法注解
public interface TimeRecord {
}
然后在原来计时的方法上来使用 annotation 来指明要使用的注解 接下来只要是添加了自定义的注解都会执行这里的方法 通过这种方式就实现了想要给哪个方法生效就直接加上注解就可以了
除了自定义注解其他现存的注解也是可以这样使用的 例如可以把RequestMapping的路径写在annotation里就表示只要加了RequestMapping的方法都可以生效