Spring AOP

刚看到Spring AOP的时候,小编也是很是吃惊,在怀疑Spring AOP到底是啥??那么,欢迎对Spring AOP感兴趣的各位老铁更深入的探讨本文:

  1. 什么是AOP??

AOP(Aspect Oriented Programming):面向切面编程,它是一种思想,它是对某一类事情的集中处理,比如:用户登录权限的校验,没学AOP之前,我们所有需要判断用户登录的页面(中的方法),都要各自实现或调用用户验证的方法,然而有了AOP之后,我们只需要在某一处配置以下,所有需要批判的用户登录页面(中的方法),就全部可以实现用户登录验证了,不再需要每个方法都写相同的用户登录验证了,而AOP是一种思想,而Spring AOP是一个框架,提供了对AOP思想的实现,他们的关系和IoC与DI类似!

对于这种功能统一,且使用的地方较多的功能,就可以考虑AOP来统一处理了,除了统一用户登录判断之外,AOP还可以实现:

  • 统一日志处理
  • 统一方法执行时间处理
  • 统一的返回格式设置
  • 统一的异常处理
  • 事务的开启和提交
  • ..................

也就是说,使用AOP可以扩充多个对象的某个能力,所以AOP可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

我们在AOP学习过程中,主要学习以下三个部分:

  1. 学习AOP是如何组成的??也就是学习AOP组成的相关概念
  2. 学习Spring AOP使用
  3. 学习Spring AOP实现原理

有了上述主要学习的三个方面,那么,来跟着小编思路来看一下吧!

AOP相关概念:

  1. 切面(Aspect)【类】:切面是AOP的核心概念,表示一个关注点的模块化,它跨越多个对象,包含了通知和切入点。切面可以理解为是在程序执行过程中特定的代码片段,它可以在程序的不同地方被执行,比如方法的前置或后置处理、异常处理等。

  2. 连接点(Join point):连接点是程序执行过程中可以插入切面的点,它表示某个特定的方法调用、异常抛出、变量赋值等程序执行的位置。

  3. 通知(Advice)【方法具体实现代码】:通知是切面具体的执行内容,即在连接点上执行的逻辑代码。通知包括了切面的具体操作,比如方法的前置、后置、环绕、异常等处理。

  4. 切入点(Pointcut):切入点是一个表达式,用于确定哪些连接点会被应用切面的通知。通过切入点可以定义切面将要发生作用的地方,以便于将切面应用到特定的方法调用上。

  5. 引入(Introduction):引入是一种动态地为类添加方法和属性的方式,可以让一个类在运行时实现额外的接口或者属性等。

  6. 织入(Weaving):织入是将切面应用到目标对象并创建新的代理对象的过程。织入可以是编译期、类加载期或者运行时进行。

看着上述内容很多,其实是由AI生成的!!(尴尬),那么,我们来看一下主要了解的相关概念吧!

  1. 切面【类】:指的是某一方面的具体内容就是一个切面,比如用户的登录判断就是一个"切面",而日志的统计记录它又是一个"切面";
  2. 切点【方法】:定义(一个)拦截器。
  3. 通知【方法具体实现代码】:执行AOP逻辑业务 a.前置通知(@Before):在目标方法(实际要执行的方法)调用之前执行的通知。

    b.后置通知(@After):在目标方法调用之后执行的通知。

    c.环绕通知(@Around):在目标方法调用前后都执行的通知(方法执行时间)。

    d.异常通知(@AfterThrowing):在目标方法抛出异常的时候执行的通知(声明事务)。

    e.返回通知(AfterReturning):在目标方法返回的时候执行的通知。

  4. 连接点:所有可能触发切点的点就叫连接点,比如:这里定义的切点是判断用户登录状态,此时我想去发布文章,发布文章就会触发去检查登录状态,这就是连接点。

有了上述些许知识储备,我们来看一下如何来实现Spring AOP吧!

实现Spring AOP:

  1. 添加Spring Boot AOP框架《------》Maven仓库(只能通过Maven仓库添加)

    由于小编使用的是JDK8,因此选择了2.x.xx版本(适用于JDK8)

    复制代码
    <!-- 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.18</version>
    </dependency>

    将上述的框架插入到IDEA中pom.xml文件中即可,然后刷新Maven下载依赖即可。

  2. 创建切面

    复制代码
    //创建切面
    @Aspect  //切面
    @Component  //不能省略《------》随着项目启动而启动
    public class UserAOP {
    
    }
  3. 创建切点:(定义拦截规则)

    复制代码
    @Aspect  //切面
    @Component  //不能省略《------》随着项目启动而启动
    public class UserAOP {
        
        //切点(配置拦截规则)
        @Pointcut("execution(* com.example.demo.AOP.*(..))")
        public void pointcut(){
            //空方法,不需要有实现,只是提供拦截规则。
        }
    
    }

    对于上述创建切点(配置拦截规则)的解析:

  4. 创建通知 以前置通知为列:

    复制代码
        //前置通知
        @Before("pointcut()")
        public void doBefore(){
            System.out.println("执行了前置通知: "+ LocalDateTime.now());
        }

    注意,在这个代码中,pointcut()是个空方法

  5. 创建连接点(连接点:所有能触发切点的点)

    复制代码
    @RestController
    public class UserController {
    
        @RequestMapping("user/sayHi")
        public String sayHi(){
            System.out.println("执行了sayHi()方法");
            return "hi spring boot aop";
        }
    
        @RequestMapping("/user/login")
        public String login(){
            System.out.println("执行了login()方法");
            return "do user login";
        }
    }

该段内容主要围绕前置通知来展开,但是,对于后置通知,返回通知《------》大致代码都差不多,主要还是注解的不同!所以,小编便不再进行展开!

但是,对于环绕通知则有稍微复杂性,那么,我们接下来便看一下环绕通知相关代码吧!!

复制代码
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint)throws Throwable{
        //ProceedingJoinPoint  事件本身
        System.out.println("开始执行环绕通知:");
        Object obj=joinPoint.proceed(); //中间执行的方法
        System.out.println("结束环绕通知~~");
        return obj; //需要吧执行的结果还给框架,让框架继续zou后续的流程
    }

经过上述的代码,我们来进一步了解Spring AOP的实现原理吧!!

Spring AOP的实现原理:

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

Spring AOP支持JDK Proxy和CGLIB方式实现动态代理,默认情况下实现了接口的类,实现AOP会基于JDK生成代理类,没有实现接口的类,会基于CGBIB生成代理类。

Spring 的切面由包裹了目标对象的代理类实现,代理类处理方式的调用执行了额外的切面逻辑,并调用目标方法。

Spring AOP实现原理:JDK的动态代理和CGLIB动态代理实现的!!

JDK动态代理和CGLIB动态代理都是常见的动态代理实现技术,但是他们有以下区别:

  1. JDK动态代理基于接口,要求目标对象实现接口;CGLIB动态代理基于类,可以代理没有实现接口的目标对象。
  2. JDK动态代理使用java.long.reflect.Proxy和java.long.reflect.InvocationHandler来生成代理对象;CGLIB动态代理使用CGLIB库来生成代理对象。
  3. JDK动态代理生成的代理对象是目标对象的接口实现**;** CGLIB动态代理生成的代理对象是目标对象的子类。
  4. JDK动态代理性能相对较高,生成代理对象速度较快;CGLIB动态代理性能相对较低,生成代理对象速度较慢。
  5. JDK动态代理无法代理fianl类和final方法;CGLIB动态代理可以代理任意类的方法。

注:在Spring框架中,即使使用了JDK动态代理,又使用了CGLIB动态代理,默认情况下使用的是JDK动态代理,但是,如果目标对象没有实现接口,则会使用CGLIB动态代理。

相关推荐
It's now1 小时前
Spring AI 基础开发流程
java·人工智能·后端·spring
cxh_陈1 小时前
线程的状态,以及和锁有什么关系
java·线程·线程的状态·线程和锁
计算机毕设VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue图书商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
R.lin1 小时前
Java 8日期时间API完全指南
java·开发语言·python
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 高校教学质量监控平台为例,包含答辩的问题和答案
java·eclipse
高山上有一只小老虎2 小时前
翻之矩阵中的行
java·算法
火钳游侠2 小时前
java单行注释,多行注释,文档注释
java·开发语言
曼巴UE52 小时前
UE FString, FName ,FText 三者转换,再次学习,官方文档理解
服务器·前端·javascript
code bean2 小时前
【CMake】为什么需要清理 CMake 缓存文件?深入理解 CMake 生成器切换机制
java·spring·缓存
selt7912 小时前
Redisson之RedissonLock源码完全解析
android·java·javascript