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动态代理。

相关推荐
YAy1731 分钟前
CC3学习记录
java·开发语言·学习·网络安全·安全威胁分析
代码小鑫32 分钟前
A035-基于Spring Boot的企业内管信息化系统
java·开发语言·spring boot·后端·spring
qq_35323353892 小时前
【原创】java+ssm+mysql校园疫情防控管理系统设计与实现
java·mvc·javaweb·ssm框架·bs·疫情防控
前端郭德纲2 小时前
浅谈React的虚拟DOM
前端·javascript·react.js
2401_879103683 小时前
24.11.10 css
前端·css
ComPDFKit4 小时前
使用 PDF API 合并 PDF 文件
前端·javascript·macos
yqcoder4 小时前
react 中 memo 模块作用
前端·javascript·react.js
代码调试5 小时前
Springboot校园失物招领平台
java·spring boot
优雅永不过时·5 小时前
Three.js 原生 实现 react-three-fiber drei 的 磨砂反射的效果
前端·javascript·react.js·webgl·threejs·three
camellias_6 小时前
SpringBoot(二十三)SpringBoot集成JWT
java·spring boot·后端