Spring in Acton 4 读书笔记之 AOP 原理及 Spring 对 AOP 的支持

字数1,504 大约花费5分钟

目录

  1. 1. AOP 各个部分的概念和作用(Defining AOP terminology)
  2. 2. Spring 对 AOP 的支持
  3. 3. Spring 的 AOP 框架的要点
    1. 3.1. Spring 的 advice 是用 Java 写的
    2. 3.2. Spring 在运行时应用 aspect
    3. 3.3. Spring 只支持方法级别的 join point

Spring in Action(Spring 实战)的第四章第一节(4.1 What is aspect-oriented programming)讲述了 AOP 原理及 Spring 对 AOP 的支持。有关 AOP 的主要思想和优点,可以参看这篇笔记《Spring in Action》第四版第一章《将 Spring 付诸实践》读书笔记(一)。本文将讲解 AOP 的各个组成部分、使用方式,以及 Spring 对 AOP 的支持。

最近在看美剧《西部世界》,我就结合书中的例子用西部世界的机器人来举例吧。

AOP 各个部分的概念和作用(Defining AOP terminology)

aop 各个部分的概念

如图所示,在程序执行过程中,在其中执行某些特定任务的过程前后,需要执行一些操作。join point 代表要执行额外动作的场景,advice 则定义哪个时间点 (任务执行前还是执行后) 要做哪些额外操作,但 advice 还不知道要关注哪些场景。pointcut 告诉每一个 advice 要执行操作的场景。这样就完整地定义了在哪些场景下、场景执行的哪个时间点下执行哪些动作了。这样听起来有些抽象。举个例子吧。

美剧《西部世界》里的游乐场,给很多机器人编写了脚本,让它们按照具体进行行动。假设其中一个观众机器人去剧场看一场表演。好了,观众到了剧场,在表演开始前,她要关闭手机。并且在表演开始前,她要坐下。在表演结束后,她要鼓掌。如果在表演过程中,表演由于设备故障无法继续,她要喊退票(^_^)。如果我们只把 advice 告诉这位机器人,那么她的知识是,她知道自己有四种任务,在某些事情开始前,她要做关闭手机和坐下两件事,在某些事情开始前,她要在坐下。某些事情结束后,她要鼓掌,如果在某些事情进行过程中,出了异常,她要喊退票。她不知道是某些事情到底是哪些事情。这时候,再告诉她,这些事情都是指一场表演。那她就知道该在什么时候做什么了。advice 和 pointcut 合起来就是 aspect,构成了所有需要知道的信息。

接下来解释 weaving 这个术语,weaving 是将 aspect 应用到一个具体的对象的 join point 上。这个动作由 spring 等框架在目标对象的以下生命周期完成:

  • 编译时应用。在编译目标类的时候应用 aspect,这需要一个特殊的编译器,AspectJ 的 weaving 编译器就是通过这种方式应用 aspect 的。
  • 加载类的时候,在将目标类加载到 JVM 的时候应用 aspect,这需要一个特殊的 ClassLoader,用来在目标类被引入应用程序之前,先访问目标类的二进制代码。AspectJ 5 的 load-time weaving(LTW)支持通过这种方式应用 aspect。
  • 运行时应用。 在应用程序执行的某个时候应用 aspect, 特别地,AOP 的容器动态生成目标对象的代理对象,以应用 aspect。这也是 Spring 的方式。

Spring 对 AOP 的支持

不同框架对 AOP 有不同程度的支持。Spring 对 AOP 的支持包含四方面:

  1. Spring 基于代理的经典的 AOP
  2. 使用 XML 配置将纯 POJO 转化为 aspect
  3. 使用 Spring 的 @Aspect 标签,创建 aspect
  4. Spring 不创建 aspect,只注入(引用)AspectJ 框架的 aspect

前面三种都是 Spring 自己的 AOP 实现,特点是基于动态代理,而且只能作用在方法级别。

其中第一种,Spring 基于代理的经典的 AOP 已经过时了,这里不再描述。

第二种方式,是使用 Spring 的 aop 包,将纯 POJO 转化成 aspect,再应用到目标类上。这种方式需要使用 XML 配置,但能够很容易地将 POJO 转化为 aspect。

第三种方式,Spring 借用 AspectJ 的 aspect 来实现标签驱动的 AOP. 底层使用的仍然是 Spring 基于代理的 AOP, 但是编程模型更像 AspectJ。这种方式的好处是不用使用 XML 配置。

第四种方式,Spring 并不负责创建 aspect 的 bean,而是由 AspectJ 创建 bean,Spring 注入(引用)bean。

Spring 的 AOP 框架的要点

Spring 的 advice 是用 Java 写的

其中,pointcuts 除了用 java 的标签之外,也可以用 xml 配置,但 java 开发人员对此都很熟悉。与 Spring 不同的是,AspectJ 框架使用的不是纯粹的 java,这样,虽然功能更强大,但也增加了学习成本。

Spring 在运行时应用 aspect

代理类接管方法调用,执行额外的逻辑,然后再调用目标方法

Spring 在运行时,通过代理类,将 aspect 应用到 Spring 管理的 bean 中。当调用一个类的方法时,代理类解析该方法调用,再执行面向方面的逻辑代码,最后,执行被调用的原始类的方法。也就是说,代理在执行目标类的方法之前,执行了额外的面向方面的业务逻辑。

只有当应用程序需要时,Spring 才会生成代理类的实例。如果使用 ApplicationContext,只有在从 BeanFactory 加载完了所有的 bean 之后,才会创建代理用的 bean。

由于 Spring 在运行时创建代理,所以不需要使用特殊的编译器,将 aspect 应用到 join point 中。

Spring 只支持方法级别的 join point

Spring 不支持将 aspect 应用到 field 级别,所以不能用来更新字段。Spring 不支持构造函数,所以在 bean 初始化的时候,无法使用 AOP。大部分情况下,Spring 对 AOP 的支持是够用的,如果不够用,可以使用上面说第四种方式,增强功能。

谈谈 IT的文章均为原创或翻译(翻译会注明外文来源),转载请以链接形式标明本文地址: http://tantanit.com/springinacton4-du-shu-bi-ji-zhi-aop-yuan-li-ji-spring-dui-aop-de-zhi-chi/

谈谈IT

欢迎关注官方微信公众号获取最新原创文章