梳理 Spring AOP

本文是关于Spring AOP 的一部分知识梳理,用来更好的理解Spring AOP。

AOP, AspectJ, Spring AOP 初步理解

先把概念搞清楚:

  • AOP: 面向切面编程的缩写,主要的作用是要在我们原来写的代码的基础上就行一些处理包装,从而实现在方法的执行前后,方法异常抛出等场景下进行增强处理。
  • AspectJ:java语言面向切面编程的完整解决方案,来自Eclipse基金会。
  • Spring AOP:spring实现的基于AOP思想的一种实现,一般和spring core结合使用。

Spring AOP

  • Spring AOP是运行时增强,是基于动态代理实现的,默认是使用基于接口的JDK动态代理实现的,如果代理类未实现接口则使用CGLIB实现。
  • Spring AOP 只能作用于Spring容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方法。
  • 尽管我们平时代码中对切面类使用的注解是@Aspect,但是实际我们使用的就是Spring AOP,Spring AOP 仅仅是引用了 AspectJ 的关于面向切面编程的一些专业术语以及它的注解包(稍后讲),底层实现和AspectJ是无关的。
  • Spring AOP仅实现了企业级开发最常用的方法切入,并没有AspectJ那么完整的功能,但就这个我们也就够用了。

AspectJ

  • AspectJ是编译时增强,属于静态织入实现,它是通过编译器修改字节码来实现的。
  • AspectJ 的织入时机:

    Compile-time weaving:编译期织入,如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
    Post-compile weaving:也就是已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。
    Load-time weaving:指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法。1、自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加载到 JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。2、在 JVM 启动的时候指定 AspectJ 提供的 agent:-javaagent:xxx/xxx/aspectjweaver.jar。

AOP 的几个名词概念

  • Advice(通知):在AOP中切面的工作被称为通知。(Spring AOP支持五种切面类型或者叫通知类型 1.前置通知 2.后置通知 3.返回通知 4.异常通知 5.环绕通知 )
  • Join point(连接点):连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为,but,Spring AOP 仅支持方法级别的切入。
  • Poincut(切点):如果说通知定义了切面的“什么”和“何时”的话,那么切点就定义了“何处”。切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点,举个栗子 execution(* com.zsyl.common.utils.RedisUtils.*(..)) 这个就是我们常用的用来进行方法切点的定义,表示要切入RedisUtils类的所有方法中。
  • Aspect(切面):切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。
  • Weaving(织入):我们梳理下织入方式,目前已知的有四种,AspectJ使用三种,Spring AOP 使用一种。
    • 编译期织入:切面在目标类编译时织入。这种方式需要特殊的编译器。AspectJ使用了该方式。
    • 编译后织入:编译后织入和编译期织入的不同在于,织入的是class字节码或者jar文件。这种形式,可以织入一个已经织入过一次的切面。同样这种情况也需要特殊的编译器。
    • 加载期织入:指的是在加载类的时候进行织入,可以自定义ClassLoader或者使用agent进行处理。
    • 运行期织入:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。Spring AOP就是使用这种方式织入切面的。

文章关于AOP术语解释参考 Spring实战(第4版) 推荐大家学习阅读哦。