
一、AOP面向切面编程切面是指某一个特定的问题AOP就是面向特定的方法编程例如登录拦截器统一数据返回统一异常处理都是使用AOP思想。AOP是Spring框架的第二大核心。二、Spring AOP也是AOP的一种实现编写AOP程序记录Controller每个方法执行的时间切点Pointcut切点就是一组规则告诉程序哪些方法进行功能加强切点表达式例如代码中连接点满足切点表达式的方法就是连接点路径下的方法都是连接点通知 Advice通知就是具体要做的工作即共同重复的逻辑例如记录多个方法的耗时切面切点通知即切面类切面所在的类即被Aspect修饰的类通知类型1. Before 前置通知执行时机目标方法执行之前运行2. AfterReturning 后置返回通知执行时机目标方法正常执行完毕、成功返回结果后异常不执行3. AfterThrowing 异常通知执行时机目标方法抛出异常时执行4. After 最终通知执行时机无论目标方法是正常结束还是抛出异常该通知都会在最后执行。5. Around 环绕通知功能最强执行时机包裹目标方法手动控制方法执行package com.bite.springaopdemo.aspect; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; Aspect Component Slf4j public class AspectDemo1 { //添加环绕通知 Around(execution(* com.bite.springaopdemo.controller.*.*(..))) public Object recordTime(ProceedingJoinPoint pjp)throws Throwable{//pjp指的是连接点对象 //记录方法开始时间 long beginSystem.currentTimeMillis(); log.info(Around方法开始执行); //执行原始方法 Object resultpjp.proceed(); //记录方法执行结束时间 long endSystem.currentTimeMillis(); log.info(pjp.getSignature()执行耗时{}ms,end-begin);//getSignature()被拦截对象的类名方法名 log.info(Around方法执行结束); return result; } //前置通知 Before(execution(* com.bite.springaopdemo.controller.*.*(..))) public void doBefore(){ log.info(执行before方法); } //后置通知 After(execution(* com.bite.springaopdemo.controller.*.*(..))) public void doAfter(){ log.info(执行after方法); } // //返回后通知 AfterReturning(execution(* com.bite.springaopdemo.controller.*.*(..))) public void doAfterReturning(){ log.info(执行afterReturning方法); } //抛出异常后通知 AfterThrowing(execution(* com.bite.springaopdemo.controller.*.*(..))) public void doafterThrowing(){ log.info(执行AfterThrowing方法); } }测试接口package com.bite.springaopdemo.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/test) public class TestController { RequestMapping(/t1) public Integer t1(){ System.out.println(执行方法); return 1; } }出现异常时候afterReturning标识方法不会执行AfterThrowing标识的通知执行Around环绕方法有异常的时候环绕后的代码不会在执行了PointCut将公共代码提取出来没有规定切面类的优先级的时候1、Before目标方法执行之前多个切面的前置通知按照切面类名称字典顺序执行 Demo1 排在前面 → Demo2 → Demo3越靠后的切面Before 越晚执行。2、After目标方法执行之后最终通知Spring AOP 采用栈结构执行先进后出。 想象成套盒子 先套上 Demo1 盒子 → 再套 Demo2 盒子 → 最后套 Demo3 盒子 执行完目标方法之后拆盒子要从最外层开始拆 先拆掉最外面的 Demo3 → 再拆 Demo2 → 最后拆 Demo1。所以 Before 入栈顺序1 → 2 → 3 After 出栈顺序3 → 2 → 1可以使用注解Order(优先级数值)数值越小优先级越高执行越早。切点表达式(具体)1.executionexecution(访问修饰符? 返回值类型 包路径.类名.方法名(参数列表) 异常抛出?)Pointcut(execution(* com.bite.springaopdemo.controller.*.*(..)))*匹配任意单个内容..匹配多层包 / 任意个参数2.annotation1.创建有一个注解类2.切面类(定义切点只对MyAspect生效)3.添加自定义注解4.测试结果Spring AOP实现方式1.基于注解Aspect2.基于自定义注解3.基于Spring API(通过xml配置的方式4.基于代理实现三、Spring AOP原理基于动态代理实现的分为1.代理模式提供一个代理类让我们调用目标方法的时候可以通过目标方法简介调用根据代理创建的时期分为静态代理和动态代理静态代理程序运行前代理类的.class文件就已经存在动态代理不需要为每个对象目标创建一个代理对象而是把代理对象的工作推迟到程序运行时由JVM实现即”业务来了再创建“java对动态代理进行了实现常见实现方式时JDK动态代理CGLIB动态代理CGLIB和JDK区别1.CGLIB能够代理接口和类JDK只能代理接口2.据说CGLIB的性能更高StringAOP 使用的是 JDK 还是 CGlib 什么时候使用 JDK 什么时候使用 CGlibproxyTargetClass是 Spring AOP 的一个配置项proxyTargetClass 值目标类情况使用代理方式false实现了接口JDK 代理false没有实现接口只有类CGLIB 代理true实现了接口CGLIB 代理true没有实现接口CGLIB 代理proxyTargetClassfalse默认旧版本规则优先 JDK 代理类实现接口才用 JDK没接口自动用 CGLIBproxyTargetClasstrue强制全部使用 CGLIB 代理不管这个类有没有实现接口。三、版本差异重点SpringBoot2.x 和 3.x 不一样Spring Framework 原生框架proxyTargetClassfalse默认值SpringBoot 2.x 版本默认也是false优先 JDK 代理SpringBoot 3.x 默认值改成 trueSpringBoot3 全局默认强制使用 CGLIB 代理不管你的 Bean 有没有实现接口统一 CGLIB。这就是为什么你用 SpringBoot3 做 AOP 的时候不需要写接口也能正常切面拦截SpringBoot2 不写接口就会报错。