1. 什么是AOP?
AOP(Aspect Oriented Programming):面向切面编程。
面向切面编程是一种思想,其实就是对某一类事情进行统一的处理。而 SpringAOP就是一种AOP的具体实现的框架。这就好比 IOC 和 DI 一样的关系。
上述就是对登录功能进行了一个统一的处理!
2. AOP能用来干些什么?
除了上面的判断登录之外,还有:
- 统一日志记录
- 统一的方法执行时间统计
- 统一的返回格式设置
- 统一的异常处理
- 事务的开启和提交
3. 学习AOP
3.1 AOP的组成
3.1.1 切面(Aspect)
切面:定义的是事件,也就是AOP是用来做啥的。
例如:用来做用户登录校验
3.1.2 切点(Pointcut)
切点:定义具体拦截规则。
例如:哪些接口需要判断用户登录,哪些不需要
3.1.3 通知(Advice)
通知:定义AOP具体的执行方法。
例如:从 Session 中获取用户信息,如果获取到则是登录,没获取到表示未登录。
3.1.4 连接点(Jion Point)
连接点:有可能触发切点的所有点,也就是所有接口。
3.2 SpringAOP实现
3.2.1 添加依赖
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-aopartifactId>
dependency>
3.2.2 定义切面
@Aspect // 表示这个为切面
@Component
public class UserAspect {
}
上述中,@Aspect注解表示这个类为切面类。@Component表示这个类随着SpringBoot启动而启动。
3.2.3 定义切点
@Aspect // 表示这个为切面
@Component
public class UserAspect {
// 定义切点
@Pointcut("execution(* com.example.springaop.controller.UserController.*(..))")
public void pointcut(){}
}
使用@Pointcut注解进行定义切点,格式为 :
excution() ,一般修饰符和异常可省略。
3.2.4 执行通知
@Aspect // 表示这个为切面
@Component
public class UserAspect {
// 定义切点
@Pointcut("execution(* com.example.springaop.controller.UserController.*(..))")
public void pointcut(){}
// 前置通知
@Before("pointcut()")
public void doBefore(){
System.out.println("执行了前置通知");
}
// 后置通知
@After("pointcut()")
public void doAfter(){
System.out.println("执行了后置通知");
}
// 返回之后通知
@AfterReturning(value = "pointcut()",returning = "")
public void doAfterReturning(){
System.out.println("执行了返回之后通知");
}
// 异常通知
@AfterThrowing("pointcut()")
public void doAfterThrowing(){
System.out.println("执行了异常通知");
}
// 环绕通知
@Around("pointcut()")
public Object doAroud(ProceedingJoinPoint joinPoint){
Object result = null;
System.out.println("环绕通知执行之前");
try {
// 执行目标方法
result = joinPoint.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
System.out.println("环绕通知执行之后");
return result;
}
}
可以通过下面看到执行顺序:
4. SpringAOP实现原理
SpringAOP是构建在动态代理的基础上实现的,因此 Spring 对 AOP 支持局限于方法级别上。
- JDK Proxy:默认情况下,实现了接口的类,使用 AOP 基于 JDK 生成代理类
- CGLIB:默认情况下,没有实现接口的类,通过实现代理类的子类来实现动态代理(被final修饰的类不能代理)
- 两者底层都是通过反射
JDK 和 CGLIB 区别:
- JDK来自JAVA;CGLIB属于三方
- JDK:是通过实现类接口的类来生成代理类;CGLIB是通过实现了代理类的子类来实现动态地理
- JDK7之后版本,JDK Proxy性能高于 CGLIB;JDK7之前,CGLIB 性能远远高于 JDK Proxy