spring(三)高级

254 阅读5分钟

AOP介绍

  • 什么是AOP

    • 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面
    • 作用:在不修改目标类代码的前提下,可以通过AOP技术增强目标类的功能,通过【预编译方式】和【运行期动态代理】实现程序功能的统一维护的一种技术
    • AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
    • AOP最早是由AOP联盟组织提出的,制定了一套规范,spring将AOP思路引入到框架中必须遵守AOP联盟规范
    • AOP是OOP的延续,是软件开发中的一个热点,也是spring框架中的一个重要内容,是函数式编程的一种衍生范型
    • 利用AOP可以对业务代码中【业务逻辑】和【系统逻辑】进行隔离,从而使得【业务逻辑】和【系统逻辑】之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  • 为什么使用AOP

    • 作用:AOP采取横向抽取机制,补充了传统纵向继承体系(OOP)无法解决的重复性代码优化(性能监视、事务管理、安全检查、缓存),将业务逻辑和系统处理代码(关闭连接、事务管理、操作日志记录)解耦
    • 优势:重复性代码被抽取出来之后,维护更加方便
    • 纵向继承体系

微信截图_20210716171550.png

 - 横向抽取机制
 

微信截图_20210716171619.png

AOP相关术语

术语解释

  • Joinpoint(连接点)

    连接点是指那些被拦截到的点,在spring中,这些点指的是方法,因为spring只支持方法类型的连接点

  • Pointcut(切入点)

    切入点是指我们要对哪些Joinpoint进行拦截的定义

  • Advice(通知/增强)

    通知是指拦截到Joinpoint之后所要做的事情,通知分为前置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

  • Introduction(引介)

    引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field

  • Target(目标对象)

    代理的目标对象

  • Weaving(织入)

    把通知应用到目标对象来创建新的代理对象的过程

  • Proxy(代理)

    一个类被AOP织入通知后,就产生一个结果代理类

  • Aspect

    是切入点和通知的结合

  • Advisor(通知器、顾问)

    和Aspect很相似

AOP之AspectJ

  • AspectJ是一个Java实现的AOP框架,它能够对Java代码进行AOP编译(一般在编译期进行),让Java代码具有AspectJ的AOP功能(需要特殊的编译器)

  • AspectJ是目前实现AOP框架中最成熟,功能最丰富的语言。AspectJ与Java程序完全兼容,几乎是无缝关联

  • AspectJ应用到Java代码的过程(这个过程称为织入),对于织入这个概念,可以简单理解为aspect(切面)应用到目标函数(类)的过程

  • 对于织入这个过程,一般分为动态织入和静态织入,动态织入的方式是在运行时动态将要增强的代码织入带目标类中,这样往往是通过动态代理技术完成的,如Java JDK的动态代理(Proxy,底层通过反射实现)或者CGLIB的动态代理(底层通过继承实现),Spring AOP采用的就是基于运行是增强代理技术

  • AspectJ采用的就是静态织入的方式,AspectJ主要采用的是编译期织入,在这个期间使用AspectJ的acj编译器(类似javac)把aspect类编译成class字节码后,在Java目标类编译时织入,即先编译aspect类再编译目标类

AOP实现之Spring AOP

  • JDK动态代理

  • CGLIB动态代理

  • 使用

    • 使用ProxyFactoryBean创建

    • 使用aop:advisor定义通知器的方式,实现AOP则需要通知累实现Advice接口

    • 增强(通知)的类型有:

      • 前置通知:org.springframework.aop.MethodBeforeAdvice

      • 后置通知:org.springframework.aop.AfterReturningAdvice

      • 环绕通知:org.aopalliance.intercept.MethodInterceptor

      • 异常通知:org.springframework.aop.ThrowsAdcice

基于AspectJ的AOP使用

其实就是指Spring + AspectJ整合,不过spring已将AspectJ收录到自身的框架中了,并且底层织入采取的是动态织入方式
  • 添加依赖

微信截图_20210716160817.png

  • 编写目标类和目标方法

    • 编写接口和实现类(目标类)
      UserService接口
      UserServiceImpl实现类
    
    • 配置目标类,将目标类交给spring

    <context:component-scan base-package="com.XXX.XXX" />

使用XML实现

- 编写通知(增强类)
- 配置通知,将通知类交给spring IoC容器管理
- 配置AOP切面

微信截图_20210716163805.png

  • 切入点表达式

    • 切入点表达式的格式 execution([修饰符] 返回值类型 包名.类名.方法名(参数))

    • 表达式格式说明

      • execution:必须要

      • 修饰符:可省略

      • 返回值类型:必须要,但是可以使用*通配符

      • 包名

        • 多级包之间使用.分割
        • 包名可以使用代替,多级包可以使用多个代替
        • 如果想省略中间的包名可以使用 ..
      • 类名

        • 可以使用*代替
        • 也可以写出*Impl
      • 方法名

        • 可以使用*代替
        • 也可以写成add*
      • 参数

        • 参数可以使用*代替
        • 如果有多个参数,可以使用 ..代替
  • 通知类型

    通知类型(五种):前置通知、后置通知、最终通知、环绕通知、异常抛出通知

    • 前置通知

      • 执行时机:目标对象方法之前执行通知
      • 配置文件<aop:before mothod="brfore" pointcut-ref="myPointCut" />
      • 应用场景:方法开始是可以进行校验
    • 后置通知

      • 执行时机:目标对象方法之后执行通知,有异常则不执行了
      • 配置文件<aop:after-returning mothod="afterReturning" pointcut-ref="myPointCut" />
      • 应用场景:可以修改方法的返回值
    • 最终通知

      • 执行时机:目标对象方法之后执行通知,有没有异常都会执行
      • 配置文件<aop:after mothod="after" pointcut-ref="myPointCut" />
      • 应用场景:可以释放资源
    • 环绕通知

      • 执行时机:目标对象方法之前和之后都会执行
      • 配置文件<aop:around mothod="around" pointcut-ref="myPointCut" />
      • 应用场景:事物,统计代码执行时机
    • 异常抛出通知

      • 执行时机:在抛出异常后通知
      • 配置文件<aop:after-throwing mothod="afterThrowing" pointcut-ref="myPointCut" />
      • 应用场景:包装异常

使用注解方式实现

  • 编写切面类(注意不是通知类,因为该类中可以指定切入点)

微信截图_20210716172915.png

  • 配置切面类

    <context:component-scan base-package="com.XXX.XXX.aop"></context:component-scan>

  • 开启AOP自动代理

     <!-- 开启aspectj的自动代理,用于AOP的注解方式 -->
    <aop:aspectj-autoproxy/>
    

纯注解方式

5FCFE147-6A87-4631-B3D3-2BC2A4574177.png