Spring AOP 的实现及原理

什么是 Spring AOP ?

AOP 是啥 ?

我们知道 OOP 是面向对象编程, 那 AOP 又是啥呢 ?

AOP(Aspect Oriented Programming):⾯向切⾯编程,它是⼀种思想,它是对某⼀类事情的集中处理。

什么又是面向切面编程?

就比如:我上 CSDN 发布文章时,它会先查询我的登录状态,我查询个人文章列表时,也要查询登录状态,查看个人主页也一样,这些功能的共同点是查询登录状态,那判断用户是否登录这件事,它就是一个切面,他就是某一类事,面向切面编程就是面向某一类事进行编程,将某一类事集中处理了。(这样就可以把精力放在业务逻辑上,而不是编写重复代码)

AOP 是⼀种思想,⽽ Spring AOP 是⼀个框架,提供了⼀种对 AOP 思想的实现,它们的关系和 IoC 与 DI 类似。

Spring AOP 可以干啥 ?

统一用户登录判断
统一日志记录
统一方法执⾏时间统计
统⼀的返回格式设置
统⼀的异常处理
事务的开启和提交等等

AOP 是针对某一类通用的事件进行统一处理,它是 OOP 的一种补充。

AOP 的组成

  1. 切面 (Aspect):定义的是什么事件(AOP 是干什么的,比如:是用户登录校验)

  2. 切点 (Pointcut):定义具体规则(定义用户拦截规则,比如:哪些接口需要判断用户登录,哪些接口不需要判断)

  3. 通知 (Advice):AOP 执行的具体方法(比如:获取用户登录信息,获取到则说明已登录)

通知又分为以下几种:
前置通知 @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。
后置通知 @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤。
返回通知 @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。
异常通知 @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。
环绕通知 @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执行自定义的行为。

  1. 连接点 (Join Point):所有可能触发切点的点(比如:所有接口)

Spring AOP 的实现

  1. 添加 Spring AOP 依赖:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-bo
ot-starter-aop -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 定义切面:
@Aspect  //表明此类为一个切面
@Component   // 随着spring框架启动而启动
public class UserAspect {
 
}
  1. 定义切点:
@Aspect  //表明此类为一个切面
@Component   // 随着spring框架启动而启动
public class UserAspect {
	// 切点,这⾥使⽤ AspectJ 表达式语法
	//拦截 UserController 里所有方法
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){   
    }
}
  1. 执行通知:

先将被拦截的类实现:

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/getuser")
    public String getUser() {
        System.out.println("do getUser");
        return "get User";
    }

    @RequestMapping("/deluser")
    public String delUser() {
        System.out.println("do delUser");
        return "del User";
    }
}
@Aspect  
@Component   
public class UserAspect {
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){
    }

    //该前置通知针对于这个切点
    @Before("pointcut()")
    public void doBefore() {
        System.out.println("执行了前置通知");
    }
}

在这里插入图片描述
在这里插入图片描述
确实是先执行前置通知,再执行被拦截的方法。

再来执行个后置通知:

    @After("pointcut()")
    public void doAfter() {
        System.out.println("执行了后置通知");
    }

再次访问:
在这里插入图片描述
在这里插入图片描述

环绕通知:

    // 添加环绕通知
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint){
        Object obj = null;
        System.out.println("Around ⽅法开始执⾏");
        try {
            // 执⾏目标⽅法
            obj = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("Around ⽅法结束执⾏");
        return obj;
    }

在这里插入图片描述
在这里插入图片描述
环绕通知是在最前面和最后面执行的。(在多线程中可以统计目标方法的执行时间,单线程下也可以使用前置通知和后置通知来统计)

Spring AOP 的实现原理

Spring AOP 是构建在动态代理基础上,因此 Spring 对 AOP 的⽀持局限于⽅法级别的拦截。

Spring 动态代理组成:

  1. JDK Proxy(代理对象必须实现接口,才能使用 JDK Proxy)
  2. CGLIB(通过实现代理类的子类来实现动态代理,被 final 修饰的类不能被代理)

JDK Proxy 和 CGLIB 区别:

  1. 实现不同:DK Proxy 要求代理类实现接口才能被代理,CGLIB 通过实现代理类的子类来实现动态代理
  2. 性能不同:JDK 7+ JDK Proxy 的性能高于 CGLIB,JDK 7 前则低于
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随风的浪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值