《Spring3实战》摘要(4-1)--面向切面的Spring

第4章 面向切面的 Spring

在软件开发中,分布于应用中多处的功能被称为横切关注点(cross-cutting concerns)。通常,这些横切关注点从概念上是与应用的业务逻辑相分离的(但是往往直接嵌入到应用的业务逻辑之中)。将这些横切关注点与业务逻辑相分离正是面向切面编程(AOP)所要解决的。

依赖注入有助于应用对象之间的解耦,而AOP可以实现横切关注点与它们所影响的对象之间的解耦。

4.1 什么是面向切面编程

这里写图片描述

在使用面向切面编程时,我们仍然在一处地方定义通用功能,但是我们可以通过声明的方式定义这个功能以何种方式在何处应用,而无需修改受影响的类。

切面关注点可以被模块化为特殊的类,这些类被称为切面。这样做有两个好处:首先,每个关注点现在都集中于一处,而不是分散到多处代码中;其次,服务模块更简洁,因为它们只包含主要关注点(或核心功能)的代码,而次要关注点的代码被转移到切面中了。

4.1.1 定义 AOP 术语

描述切面的常用术语有通知(advice)、切点(pointcut)和连接点(join point)。
这里写图片描述

(1)通知(advice)
在AOP术语中,切面的工作被称为通知。

通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。

Spring切面可以应用5种类型的通知:

通知(advice)类型说明
Before在方法被调用之前调用通知。
After在方法完成之后调用通知,无论方法执行是否成功。
After-returning在方法成功执行之后调用通知。
After-throwing在方法抛出异常后调用通知。
Around通知包裹了被通知的方法,在被通知的方法调用之前和之后执行自定义的行为。



(2)连接点(Joinpoint)
连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

(3)切点(Pointcut)
一个切面并不需要通知应用的所有连接点,切点有助于缩小切面所通知连接点的范围。

如果通知定义了切面的“什么”和“何时”,那么切点就定义了“何处”。切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称模式来指定这些切点。有些AOP框架允许我们创建动态的切点,可以根据运行时的决策(比如方法的参数值)来觉得是否应用通知。

(4)切面(Aspect)
切面是通知和切点的结合。通知和切点共同定义了关于切面的全部内容—-它是什么,在何时何处完成其功能。

(5)引入(Instroduction)
引入允许我们向现有的类添加新方法和属性。例如,我们可以创建一个 Auditable 通知类,该类记录了对像最后一次修改时的状态。这很简单,只需要一种方法 setLastModified(Date) ,和一个实例变量来保存这个状态。然后,这个新方法和实例变量就可以被引入到现有的类中。从而可以在无需修改这些现有的类的情况下,让它们具有新的行为和状态。

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

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

4.1.2 Spring 对 AOP 的支持

三大 AOP 框架:

Spring提供了4种各具特色的AOP支持:

  • 基于代理的经典 AOP;
  • @AspectJ 注解驱动的切面
  • 纯 POJO 切面
  • 注入式 AspectJ 切面(适合 Spring 各版本)。

前三种都是 Spring 基于代理的 AOP 变体,因此,Spring 对 AOP 支持局限于方法拦截。如果 AOP 需求超过了简单方法拦截的范畴(比如构造器或属性拦截)。那么应该考虑在 AspectJ 里实现切面,利用 Spring 的DI(依赖注入)把 Spring Bean 注入到 AspectJ 切面中。

4.2 使用切点选择连接点

Spring借助AspectJ的切点表达式语言来定义Spring切面。下表列出了 Spring AOP 所支持的 AspectJ 切点指示器。在 Spring 中尝试使用 AspectJ 其他指示器时,将会抛出 IllegalArgumentException 异常。

AspectJ指示器描述
arg()限制连接点匹配参数为指定类型的执行方法
@args()限制连接点匹配参数由指定注解标注的执行方法
execution()用于匹配是连接点的执行方法
this()限制连接点匹配AOP代理的Bean引用为指定类型的类
target()限制连接点匹配目标对象为指定类型的类
@target()限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型的注解
within()限制连接点匹配指定的类型
@within()限制连接点匹配指定注解所标注的类型(当使用 Spring AOP 时,方法定义在由指定的注解所标注的类里)。
@annotation限制匹配带有指定注解的连接点


上表中展示的这些 Spring 支持的指示器,只有 execution 指示器是唯一的执行匹配,而其他的指示器都是用于限制匹配的。这说明 execution 指示器是我们在编写切点定义时最主要使用的指示器。在此基础上,我们使用其他指示器来限制所匹配的切点。

4.2.1 编写切点(AspectJ切点表达式)

示例1:
这里写图片描述

注:代表方法使用任意参数的符号为两点,在方法的括号中输入三个点解析会出现错误。

示例2:
这里写图片描述

4.2.2 使用 Spring 的 bean() 指示器

Spring 2.5 还引入了一个新的 bean() 指示器,该指示器允许我们在切点表达式中使用 Bean 的 ID 来标识 Bean。bean() 使用 Bean ID 或 Bean 名称作为参数来限制切点只匹配特定的 Bean。

<!-- 示例1:在执行Instrument的play()方法时应用通知,但限定 Bean ID 为 eddie -->
exection(* com.springinaction.springidol.Instrument.play())
    and bean(eddie)
<!-- 示例2: -->
exection(* com.springinaction.springidol.Instrument.play())
    and !bean(eddie)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值