AOP思想
AOP指的是面向切面编程,跟OOP面向对象编程一样是一种思想。用一句话概括就是:在面对某一类问题时,主动进行集中处理。
例如在博客系统中,在添加博客,删除博客等场景需要验证你的身份信息,是否已经登入。以往的做法是把验证是否登入功能的代码进行封装,然后在这些板块调用它。但是这就把代码嵌入到这些板块中,耦合度高。如果未来验证是否登入功能的代码进行修改,需要传递参数变了,那么整个项目调用它的板块也要进行修改,维护成本高。而AOP就可以很好的解决这个问题,把验证用户是否登入集中处理,在添加博客,删除博客时会主动帮你处理这个问题,这就让这些板块都只完成自己的要实现的功能,耦合度就降低了。
AOP的组成
切面
通俗理解切面就是程序中一个处理某方面具体问题的一个类,类中包含很多方法,这些方法就是切点和通知
切点
配置主动拦截规则
在博客系统中,添加博客,删除博客等功能中需要验证是否用户登入,而登入功能却不需要,判断一个需不需要就是通过你配置的拦截规则来判断,如果需要就主动帮你处理。
通知
经过拦截规则的判定,如果被拦截下来,后续要实现哪些具体业务代码。
- 前置通知:在执行目标方法之前执行的方法
- 后置通知:在执行目标方法之后执行的方法
- 异常通知:在执行目标方法出现异常时,执行的通知
- 返回通知:目标方法执行了返回数据(return)时,执行的通知
- 环绕通知:在目标方法执行的周期内(执行之前,执行中,执行后)都可以执行的方法叫做环绕通知
连接点
可能触发AOP拦截规则的所有点(所有请求)
Spring AOP的实现
添加Spring AOP框架支持
xml
<!-- 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>
定义切面和切点
java
@Aspect //告诉框架我是一个切面类
@Component //随着框架的启动而启动
public class UserAop {
}
java
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) 一个整形
- (...) 参数任意
- +通配符,必须放在类后面,表示继承该类的所有子类包括自己
定义通知
java
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.