• Spring AOP 简介


    一、Spring AOP

    AOP 是一种思想,而 Spring AOP 是一个框架,提供了一种对 AOP 思想的实现。

    1、什么是 AOP?

    AOP(Aspect Oriented Programming):是一种编程思想,表示面向切面编程指的是对某一类事情的集中处理

    举一个常见的例子,当我们实现用户登录校验的时候,如果有多个网页都有同样的需求,那么我们传统的写法是在每个页面都写一个校验逻辑,这就会导致代码的可维护性降低。而如果我们使用
    AOP 的思想,就可以对这种功能一致,且多次使用的功能进行统一的处理。

    通过上面的例子,我们可以归纳出 AOP 的应用场景:

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

    对于 AOP 来说,它可以扩充多个对象的某个能力,因此通常认为 AOP 是 OOP(Object Oriented Programming,面向对象编程)的补充和完善。

    2、AOP 的组成

    切面(Aspect):定义的是事件,描述了当前 AOP 的作用。是包含了 切点和通知 的类。例如定义当前AOP是进行统一用户登录判断的。

    连接点(Join Point):连接点是在应用程序执行过程中可以插入切面的点,切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。典型的连接点包括方法调用、方法执行、异常抛出等。

    切点(Pointcut):定义匹配 Join Point 的规则,给满足规则的 Join Point 添加 Advice。例如定义哪些接口判断用户登录权限,哪些不判断。

    通知(Advice):AOP 执行方法的具体实现 。例如通过获取用户的 session 信息,判断用户登录状态。

    在Spring AOP 中提供了以下五种类型的通知:

    1. 前置通知(@Before):通知方法会在目标方法调用之前执行。
    2. 后置通知(@After):通知方法会在目标方法返回或者抛出异常后调用。
    3. 返回通知(@AfterReturning):通知方法会在目标方法返回后调用。
    4. 异常通知(@AfterThrowing):通知方法会在目标方法抛出异常后调用。
    5. 环绕通知(@Around):通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。

    二、Spring AOP 实现

    下面我们使用 Spring AOP 来完成拦截所有 UserController 里的方法,每次调用 UserController 中任意一个方法时,都执行相应的通知事件。

    1、添加 AOP 框架支持

    
    <dependency>
    	<groupId>org.springframework.bootgroupId>
    	<artifactId>spring-boot-starter-aopartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、定义切面类

    定义切面使用的是 @Aspect

    @Aspect
    @Component
    public class UserAspect {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、定义切点

    定义切点使用 @Pointcut 注解,可在参数中定义匹配 Joint Point 的规则(这里使用的是 AspectJ 语法)

    @Aspect
    @Component
    public class UserAspect {
    
        // 定义切点,使用 AspectJ 语法
        // 该切点规则将匹配 com.example.demo.controller.UserController 类
        // 中的所有方法,无论方法的返回类型和参数列表如何
        @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
        public void pointCut(){}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4、实现通知

    对于 前置通知、后置通知、返回通知、异常通知 的实现都如出一辙,并且非常简单,只需要添加给通知方法添加响应通知注解即可:

    @Aspect
    @Component
    public class UserAspect {
    
        // 定义切点,使用 AspectJ 语法
        @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
        public void pointCut(){}
    
        // 前置通知
        @Before("pointCut()")
        public void doBefore(){
            System.out.println("执行doBefore()前置通知!");
        }
        // 后置通知
        @After("pointCut()")
        public void doAfter(){
            System.out.println("执行doAfter()后置通知!");
        }
        // 返回通知
        @AfterReturning("pointCut()")
        public void doAfterReturn(){
            System.out.println("执行doAfterReturn()了返回通知");
        }
        // 异常通知
        @AfterThrowing("pointCut()")
        public void doAfterThrowing(){
            System.out.println("执行了doAfterThrowing()异常通知");
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    比较复杂的是环回通知的实现,环回通知有它固定的格式:

    @Aspect
    @Component
    public class UserAspect {
        // 定义切点,使用 AspectJ 语法
        @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
        public void pointCut() {
        }
        // 环绕通知
        @Around("pointCut()")
        public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("Around ⽅法开始执⾏");
            // 执行目标方法
            Object obj = joinPoint.proceed();
            System.out.println("Around ⽅法结束执⾏");
            return obj;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    其中 ProceedingJoinPoint 在环绕通知中可以控制目标方法的执行。通过调用 joinPoint.proceed() 可以触发目标方法的执行。如果目标方法有返回值,当目标方法执行完毕后,它会被保存在 obj 变量中,作为整个环绕通知方法的返回值返回给调用方。

    调用 UserController 中的方法,得到测试结果:

    三、Spring AOP 实现原理

    Spring AOP 是构建在动态代理基础上的。Spring 的切面是由包裹了目标对象的代理实现的,代理类处理方法的调用,执行额外的切面逻辑,并调用目标方法。

    Spring AOP 支持 JDK Proxy 动态代理和 CGLIB 动态代理技术,它们主要有以下区别:

    1. JDK Proxy 来自于 Java 本身,CGLIB 来自于第三方。
    2. JDK Proxy 动态代理是基于接口的,要求代理类必须实现接口才能实现代理;CGLIB 动态代理是基于类的,通过继承被代理类完成动态代理,因此要求被代理类不能是 final 修饰的类。
    3. 在 JDK 8 以上的版本中,JDK Proxy 动态代理做了专门的优化,所以性能比 CGLIB 高。
  • 相关阅读:
    用HTML5和JavaScript实现黑客帝国风格的字符雨效果
    QT资源文件导入
    使用领域引导图卷积神经网络GCNN增强基于脑电图EEG的神经疾病诊断完整代码
    etcd选举源码分析和例子
    AWS认证SAA-C03每日一题
    四十一、Fluent初学者学习流程
    CS5340国产替代DP5340多比特音频 A/D 转换器
    java计算机毕业设计基于springboot 房屋租赁出租系统
    11.30 - 每日一题 - 408
    UE常见变量并且在【细节面板】中进行修改
  • 原文地址:https://blog.csdn.net/LEE180501/article/details/132801470