Spring AOP 的实现及原理

目录

  • [什么是 Spring AOP ?](#什么是 Spring AOP ?)
    • [AOP 是啥 ?](#AOP 是啥 ?)
    • [Spring AOP 可以干啥 ?](#Spring AOP 可以干啥 ?)
  • [AOP 的组成](#AOP 的组成)
  • [Spring AOP 的实现](#Spring AOP 的实现)
  • [Spring AOP 的实现原理](#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 依赖:
java 复制代码
<!-- 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. 定义切面:
java 复制代码
@Aspect  //表明此类为一个切面
@Component   // 随着spring框架启动而启动
public class UserAspect {
 
}
  1. 定义切点:
java 复制代码
@Aspect  //表明此类为一个切面
@Component   // 随着spring框架启动而启动
public class UserAspect {
	// 切点,这⾥使⽤ AspectJ 表达式语法
	//拦截 UserController 里所有方法
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){   
    }
}
  1. 执行通知:

先将被拦截的类实现:

java 复制代码
@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";
    }
}
java 复制代码
@Aspect  
@Component   
public class UserAspect {
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void pointcut(){
    }

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


确实是先执行前置通知,再执行被拦截的方法。

再来执行个后置通知:

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

再次访问:

环绕通知:

java 复制代码
    // 添加环绕通知
    @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 区别:

  3. 实现不同:DK Proxy 要求代理类实现接口才能被代理,CGLIB 通过实现代理类的子类来实现动态代理

  4. 性能不同:JDK 7+ JDK Proxy 的性能高于 CGLIB,JDK 7 前则低于

相关推荐
扣丁梦想家1 小时前
RocketMQ 详细教程(Spring Boot & Spring Cloud Alibaba)
spring boot·spring cloud·微服务·rocketmq
GGGGGGGGGGGGGG.3 小时前
使用dockerfile创建镜像
java·开发语言
兮动人4 小时前
SpringBoot加载配置文件的优先级
java·spring boot·后端·springboot加载配置
我爱Jack4 小时前
HttpServletRequest 和 HttpServletResponse 区别和作用
java·spring·mvc
yyueshen4 小时前
volatile 在 JVM 层面的实现机制
java·jvm
慕容魏4 小时前
入门到入土,Java学习 day16(算法1)
java·学习·算法
认真的小羽❅4 小时前
动态规划详解(二):从暴力递归到动态规划的完整优化之路
java·算法·动态规划
m0_748254664 小时前
Spring Boot 热部署
java·spring boot·后端
mango02194 小时前
SpringMVC
java
Seven974 小时前
SpringCloud带你走进微服务的世界
java·后端·spring cloud