• Spring之AOP思想


    目录

    什么是AOP

     ​​​为什么用AOP

    Spring AOP 应该怎么学习呢

    AOP下的一些核心概念(SpringAOP并没有实现所有的概念)

    基于概念的使用Spring的AOP 

    一个使用的实例

    关于切点的匹配

    通知的种类

     使用注解的方式来实现功能​编辑

    AOP框架背后的核心 

    需要实现两个原理

    AOP的应用-事务场景

    事务的概念 

    事务的隔离性

     Spring的提供的一个事务切点@Transcctional​编辑


    什么是AOP

    • AOP面对切面编程,它是一种思想,它是对某一类事情的集中处理。比如用户获奖权限的效验,没学 AOP 之前,我们所有需要判断用户获奖权限的页面(中的方法),都要各自实现或调用用户验证的方法,然而有了 AOP 之后,我们只需要在某一处配置一下,所有需要判断用户中将权限页面(中的方法)就全部可以实现用户用户中将权限验证了,不再需要每个方法中都写相同的用户登录验证了。而 AOP 是一种思想,而 Spring AOP 是一个框架,提供了一种对 AOP 思想的实现,它们的关系和 IoC与 DI 类似。
    • Spring下的AOP,Java AOP做的比较早的AspectJ库,是相当于做的比较早,Spring的AOP的在使用方式的时候,很多也延续了AspectJ的方式

     ​​​为什么用AOP

    为什要用 AOP?想象一个场景,我们在做后台系统时,除了登录和注册等几个功能不需要做用户登录验证之外,其他几乎所有页面调用的前端控制器( Controller)都需要先验证用户登录的状态,那这个时候我们要怎么处理呢?

    • 我们之前的处理方式是每个 Controller 都要写一遍用户登录验证,然而当你的功能越来越多,那么你要写的登录验证也越来越多,而这些方法又是相同的,这么多的方法就会代码修改和维护的成本。那有没有简单的处理方案呢?答案是有的,对于这种功能统一,且使用的地方较多的功能,就可以考虑 AOP来统一处理了。
    • 在惊动原始设计的基础上进行功能增强

    除了统一的用户登录判断之外,AOP 还可以实现

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

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


    Spring AOP 应该怎么学习呢

    • 1. 学习 AOP 是如何组成的?也就是学习 AOP 组成的相关概念。

    • 2. 学习 Spring AOP 使用。

    • 3. 学习 Spring AOP 实现原理。
       

    AOP下的一些核心概念(SpringAOP并没有实现所有的概念)

    Join Point连接点

    • 连接点是在应用执行过程中能够插入切面(Aspect)的一个点
    • 程序执行过程中的任意位置,粒度为执行方法,抛出异常,设置变量等
    • Spring AOP中仅支持方法的这一个连接点,所以在使用Spring AOP的时候,不太提这个概念

    Advice通知

    • 在切入点执行的操作,也就是我们的公共业务

    Point CUT 切入点

    • 切入点是一些特使的连接点,是具体附加通知的地方
    • 哪些方法被切入,也就是哪些方法需要添加公共业务(进行功能增强)

    Aspect 切面

    • 逻辑概念,指的就是放置各种公共业务的,以及公共业务如何和具体的业务产生关系的配置的地方,
    • 切面(Aspect)由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑(我们的通知)的定义,也包括了连接点的定义。

    基于概念的使用Spring的AOP 


    Spring AOP 的实现步骤如下:

    • 1. 添加 Spring AOP 框架支持。导入相应的jar包
    • 2 定义接口和相应的实现类,也就是我们的程序,程序中的方法可以作为切入点,进行功能增强
    • 3. 定义通知类(存放我们的切面)@Aspect修饰方法,并且让这个通知类被Spring容器管理,生产对应的bean
    • 4 在通知类(切面)定义切入点,用PointCut()进行匹配对应的切入点
    • 5 进行我们的通知的定义(具体的增强功能的逻辑,用方法的形式实现),然后跟对应的切入点建立对应的联系 @Before之类
    • 6 开启对Aop注解驱动支持 (?好像SpringBoot会自动帮我们做这些配置)

    注入相应的依赖

    一个使用的实例

     定义切面

    关于切点的匹配

    • Aspectl是Java的AOP领域的领头羊,所以它的方案基本就称为Java AOP的标准存在了,所以AspectJ定义一组表达式的语法,来描述Pointcut,所以Spring AOP也使用这种表达式,Spring AOP和AspectJ(也是一种AOP框架)之间其实是没有关系的 
    • 就像我们很多聊天软件都采用了这种聊天框

    切点表达式由切点函数组成

    其中 execution() 是最常用的切点函数,用来匹配方法,语法为:execution(<修饰符><返回类型><包.类.方法(参数)><异常>) 修饰符和异常可以省略。 

    • 动作关键字:execution 描述切入点的行为动作
    • 访问的修饰符
    • 返回值
    • 包名
    • 类名/接口名(一般匹配到接口比较好,降低耦合度)
    • 方法名 具体的切入点
    • 参数 对应切入点的参数
    • 异常名 方法定义中抛出的异常,可以省略

    AspectJ 支持三种通配符:

    • * :匹配任意字符,只匹配一个元素(包,类,或方法,方法参数)。
    • .. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使用。
    • + :表示按照类型匹配指定类的所有类,必须跟在类名后面,如 com.cad.Car+ ,表示继承该类的所有子类包括本身。

    •  匹配表达式是写在@Pointcut()里面的
    • 切入点需要依靠一个无返回值的方法(最好可以是私有的),方法体是无实际逻辑的

    通知的种类

    • 前置通知使用 @Before:通知方法会在目标方法调用之前执行
    • 后置通知使用 @After:通知方法会在目标方法返回或者抛出异常后调用。
    • 返回之后通知使用 @AfterReturning:通知方法会在目标方法返回后调用
    • 抛异常后通知使用 @AfterThrowing:通知方法会在目标方法抛出异常后调用。
    • 环绕通知使用 @Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。这个方法是很万能的,理论上有了Around可以实现上面四种

    @Around的注意事项

    • 环绕通知必须依赖形参ProcessingJoinPoint才能对原始方法进行调用,进而实现原始方法调用前后的通知添加
    • 通知中若未使用ProcessingJoinPoint对原始方法执行,则会跳过原始方法的执行,这里我们可以实现权限验证
    • 对原始方法的调用可以不接收返回值,通知方法设置成void即可,但是如果接收,必须设定为Object
    • 原始方法的返回值如果是void类型,通知方法的类型也可以是void,也可以是Object
    • 由于无法原方法运行是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

     使用注解的方式来实现功能

    工作流程

    • Spring容器启动
    • 读取所有切面配置中的切入点(如果没匹配上,是不会读取的)
    • 初始化bean,判定bean对应的类中的方法是否匹配到了任意的切入点 1匹配失败,创建对象  2匹配成功,创建原始对象的代理对象
    • 获取bean的执行方法  1对于没有匹配到的连接点,直接获得原始对象的bean调用方法并执行,完成操作 2获取的是bean是原始对象的代理对象,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

    AOP框架背后的核心 

    需要实现两个原理

    对象代理

    • Spring AOP框架的核心原理,因此 Spring 对 AOP 的支持局限于方法级别的拦截
    • Spring AOP 支持 JDK Proxy 和 CGLIB 方式实现动态代理。现在Spring默认都是CGLJB方式

    JDK Proxy vs CGLIB Proxy

    • JDK 实现,要求被代理类必须实现接口,之后是通过 InvocationHandler 及 Proxy,在运行时动态的在内存中生成了代理类对象,该代理对象是通过实现同样的接口实现(类似静态代理接口实现的方式),只是该代理类是在运行期时,动态的织入统一的业务逻辑字节码来完成。
    • CGLIB 实现,被代理类可以不实现接口,是通过继承被代理类,在运行时动态的生成代理类对象。
    • JDK Proxy只能针对接口做对象代理,而CGLib可以针对任意对象代理,所以它的适用场景更广
       

    CGLib的实现代理

    织入(Weaving):代理的生成时机
    织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:

    • 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
    • 类加载器:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-timeweaving. LTW)就支持以这种方式织入切面。
    • 运行期:切面在应用运行的某一时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象。SpringAOP就是以这种方式织入切面的

    动态代理

    • 此种实现在设计模式上称为动态代理模式,在实现的技术手段上,都是在 class 代码运行期,动态的织入字节码。
    • 我们学习 Spring 框架中的AOP,主要基于两种方式:JDK 及 CGLIB 的方式。这两种方式的代理目标都是被代理类中的方法,在运行期,动态的织入字节码生成代理类。
    • CGLIB是Java中的动态代理框架,主要作用就是根据目标类和方法,动态生成代理类。
    • Java中的动态代理框架,几乎都是依赖字节码框架(如 ASM,Javassist 等)实现的。字节码框架是直接操作 class 字节码的框架。可以加载已有的class字节码文件信息,修改部分信息,或动态生成一个 class。

     简单实现

    AOP的应用-事务场景

    事务的概念 

    • 事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。就是将这一组操作作为一个整体
    • 在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务。

    其实整体的概念就是保证一致性

    • 我们就引入显式事务这种概念 来告诉MySQ几条SQL语句是一个整体
    • 如果只是一条SQL吗,其实就是一个事务,称为隐式事务

     为了保证一致的四个特性

    •  Mysql的实现者在就保证了事务的四大特性
    • Mysql的使用者就要正确的Mysql提供事务原语

    事务的隔离性

     Spring的提供的一个事务切点@Transcctional

    事务的传播级别

     

    • 1. Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
    • 2. Propagation.REQUIRES_NEW:表示创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
    • 3. Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    • 4. Propagation.MANDATORY:(mandatory:强制性)如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

    • 5. Propagation.NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    • 6. Propagation.NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
    • 7. Propagation.NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。

     

  • 相关阅读:
    每天五分钟机器学习算法:拉格朗日乘数法和KKT条件
    芯片的发展史和具体用途以及结构是什么样的
    nltk download所需包
    利用Python爬取高德地图全国地铁站点信息
    vue electron 下载Vue-devtools ChromeExtension扩展失败
    网页音频提取在线工具有哪些 网页音频提取在线工具下载
    STM32——触摸屏实验-电阻型触摸屏-M4
    无线安全操作(1)
    sqlmap结合dnslog外带注入
    flink sql clinet 实战:upsert kafka connector -- flink-1.12
  • 原文地址:https://blog.csdn.net/qq_50985215/article/details/126610966