Spring AOP
AOP(Aspect Oriented Programming):面向切编程。是对某⼀类事情的集中处理,例如网站的登录验证,不使用 AOP 的话发布文章需要一段代码进行验证、编辑文章需要验证……而使用 AOP 的话只需要在某⼀处配置⼀下,需要验证的地方都可以实现了。
AOP 是⼀种思想,而 Spring AOP 是⼀个框架,提供了⼀种对 AOP 思想的实现,它们的关系和IoC 与 DI 类似。
AOP 组成的相关概念。
1. 切面(类)
指的是某一方面的具体实现。比如用户登录判断是一个”切面“,日志记录也是一个”切面“。
2. 切点(方法)
定义的一个拦截规则,只有符合条件的才能进行下一步。
3. 通知(方法的具体实现代码)
执行 AOP 的逻辑业务
3.1 前置通知:在目标方法(实际要执行的方法)调用前执行的通知
3.2 后置通知:在目标方法调用后执行的通知
3.3 环绕通知:在目标方法调用前、后都会执行的通知
3.4 异常通知:在目标方法抛出异常的时候执行的通知
3.5 返回通知:在目标方法返回的时候执行的通知
4. 连接点
所有可能触发 切点 的点就叫做连接点。比如登录判断是一个切点,然后用户发布文章的时候会触发登录判断,这个就是连接点。
Spring AOP 实现
一开始 spring 官方没有实现 AOP,因此有个非官方的组织使用 AspectJ 来实现 AOP,后来官方也实现了 Spring AOP,但是发现很多人使用 AspectJ 的语法习惯了,因此 Spring AOP 就兼容了 AspectJ。
添加依赖
pom.xml:
org.springframework.boot
spring-boot-starter-aop
定义切面、切点、通知:
package com.example.springaopdemo.common;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect // 创建切面
@Component // 托管到 spring 容器,随着项目启动而启动
public class UserAOP {
// 创建切点
// 只会拦截符合表达式规则的,下一步是否要停止它的执行要看需求,跟过海关一样
@Pointcut("execution(* com.example.springaopdemo.controller.UserController.* (..))")
public void doPoint() {
}
// 创建通知
// 前置通知
@Before("doPoint()")
public void before() {
System.out.println("执行前置通知方法");
}
// 后置通知
@After("doPoint()")
public void after() {
System.out.println("执行后置通知方法");
}
// return前通知
@AfterReturning("doPoint()")
public void afterReturning() {
System.out.println("执行return前通知方法");
}
// 抛出异常前通知
@AfterThrowing("doPoint()")
public void afterThrowing() {
System.out.println("执行抛出异常前通知方法");
}
// 环绕通知
@Around("doPoint()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开始执行环绕通知方法");
Object obj = joinPoint.proceed();
System.out.println("结束执行环绕通知方法");
return obj;
}
}
关于切点表达式说明:
语法为:execution()
代码执行(连接点):
Spring AOP 实现原理
使用动态代理的方式实现的。Spring AOP 使用两种方式实现动态代理:
1. JDK Proxy:要求被代理的类一定要实现接口。(底层通过反射实现,速度快)
2. CGLIB:因为是通过代理类的子类来实现动态代理的,所以要求代理类不能被 final 修饰。