Spring AOP
AOP思想
AOP指的是面向切面编程,跟OOP面向对象编程一样是一种思想。用一句话概括就是:在面对某一类问题时,主动进行集中处理。
例如在博客系统中,在添加博客,删除博客等场景需要验证你的身份信息,是否已经登入。以往的做法是把验证是否登入功能的代码进行封装,然后在这些板块调用它。但是这就把代码嵌入到这些板块中,耦合度高。如果未来验证是否登入功能的代码进行修改,需要传递参数变了,那么整个项目调用它的板块也要进行修改,维护成本高。而AOP就可以很好的解决这个问题,把验证用户是否登入集中处理,在添加博客,删除博客时会主动帮你处理这个问题,这就让这些板块都只完成自己的要实现的功能,耦合度就降低了。

AOP的组成
切面
通俗理解切面就是程序中一个处理某方面具体问题的一个类,类中包含很多方法,这些方法就是切点和通知
切点
配置主动拦截规则
在博客系统中,添加博客,删除博客等功能中需要验证是否用户登入,而登入功能却不需要,判断一个需不需要就是通过你配置的拦截规则来判断,如果需要就主动帮你处理。
通知
经过拦截规则的判定,如果被拦截下来,后续要实现哪些具体业务代码。
- 前置通知:在执行目标方法之前执行的方法
- 后置通知:在执行目标方法之后执行的方法
- 异常通知:在执行目标方法出现异常时,执行的通知
- 返回通知:目标方法执行了返回数据(return)时,执行的通知
- 环绕通知:在目标方法执行的周期内(执行之前,执行中,执行后)都可以执行的方法叫做环绕通知
连接点
可能触发AOP拦截规则的所有点(所有请求)
Spring AOP的实现
添加Spring AOP框架支持
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.7.9</version></dependency>
定义切面和切点
@Aspect //告诉框架我是一个切面类
@Component //随着框架的启动而启动
public class UserAop {
}
public class UserAop {/*定义切点,配置主动拦截规则execution()切点函数,用来匹配具体哪个方法*/@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")public void pointcut() {}
}
拦截规则的配置
execution(<修饰符><返回类型><包.类.方法(参数)><异常>)
- 修饰符,一般省略
- 返回值,不能省略
- void 返回没有值
- String 返回字符串
-
- 任意
- 包
- com.example.demo.*.service demo包下任意一个包(该包的下一层是service)
- com.example.demo… demo包下的所有包(含自己)
- com.example.demo.*.service… demo包下任意包,但再下一层是service, service目录任意包
- 类
- *Controller 以Controller结尾
- User* 以User开头
-
- 任意
- 方法名,不能省略
- add* 以add开头
- *xxx 以xxx结尾
-
- 任意
- 参数
- () 无参
- (int) 一个整形
- (…) 参数任意
- +通配符,必须放在类后面,表示继承该类的所有子类包括自己
定义通知
public class UserAop {/*定义切点,配置主动拦截规则*/@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")public void pointcut() {}/*前置通知*/@Before("pointcut()")public void beforeAdvice() {System.out.println("执行了前置通知");}/*后置通知*/@After("pointcut()")public void afterAdvice() {System.out.println("执行了后置通知");}/*** 环绕通知* @param ProceedingJoinPoint 规定写法* @return 返回Object给框架*/@Around("pointcut()")public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("进入环绕通知");Object obj = null;//执行目标方法obj = joinPoint.proceed();System.out.println("退出环绕通知");return obj;}
}
Spring AOP实现原理
Spring AOP是基于动态代理实现的,因此Spring对AOP的支持局限于方法级别的拦截。
动态代理:如上图所示,调用者不能直接发送请求给目标对象,而是先发送给代理类,代理类在给你转发到目标对象。
代理的生成时期:织入
Spring AOP的代理生成时期是”运行期“,动态的织入字节码
Spring框架中的AOP实现方式有两种1.JDK proxy方式;2.CGLIB方式。在Spirng中默认是JDK方式,而在Spring boot中是CGLIB。
JDK实现要求被代理类必须实现接口,而CGLIB没有这个要求,是通过继承被代理类,所以被final修饰的代理类,无法被继承,只能选择JDK.