Spring AOP (一) 简介

面向切面编程(Aspect Oriented Programming, AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP)。OOP 中模块化的关键单元是类,而在 AOP 中,模块化单元是切面。

AOP 旨在从业务逻辑中分离出来通用逻辑,切面实现了跨越多种类型和对象的关注点(例如事务管理、日志记录、权限控制)的模块化。(这些在 AOP 文献中通常被称为 “横切” 问题。)

切面织入的三种方法:

  • 编译期织入 (Compile Time Weaving,CTW):指在 Java 编译期,采用特殊的编译器,将切面织入到 Java 类中。
  • 类加载期织入(Load Time Weaving,LTW):指通过特殊的类加载器,在类字节码加载到 JVM 时,织入切面。
  • 运行期织入:指采用 CGLIB 工具或 JDK 动态代理进行切面的织入。

AOP 的概念和术语

让我们首先定义一些重要的 AOP 概念和术语。这些术语不是特定于Spring的。不幸的是,AOP 术语不是特别直观。但是,如果 Spring 使用自己的术语,那将更加令人困惑。

  • 切面(Aspect): 跨越多个类的关注点的模块化。事务管理是企业 Java 应用程序中横切关注点的一个很好的例子。在 Spring AOP 中,切面是通过使用常规类(基于模式的方法)或使用 @Aspect 注释的常规类来实现的 。
  • 连接点(JoinPoint):程序执行期间的一个点,例如执行方法或处理异常。在 Spring AOP 中,连接点始终表示方法执行。
  • 通知(Advice):特定连接点的某个切面采取的操作。不同类型的建议包括 around, beforeafter 通知。许多 AOP 框架(包括 Spring)将通知建模为一个拦截器,并在围绕着连接点维护了一个拦截器链。
  • 切入点(Pointcut):匹配连接点的谓词。建议与切入点表达式相关联,并在切入点匹配的任何连接点处运行(例如,执行具有特定名称的方法)。由切入点表达式匹配的连接点的概念是 AOP 的核心,Spring 默认使用 AspectJ 切入点表达式语言。
  • 引介增强(Introduction):在一种类型代表上声明额外的方法或字段。Spring AOP 允许您向任何建议的对象引入新接口(以及相应的实现)。例如,您可以使用引介增强使 bean 实现 IsModified 接口,以简化缓存。
  • 目标对象(Target Object):由一个或多个切面增强的对象。也称为 advised object。由于 Spring AOP 是使用运行时代理实现的,因此该对象始终是一个被代理对象。
  • AOP Proxy:由 AOP 框架创建的对象,用于实现且切面契约(建议方法执行等)。在 Spring Framework 中,AOP 代理是 JDK 动态代理或 CGLIB 代理。
  • 织入(Weaving):将切面与其他应用程序类型或对象链接以创建 advised object。这可以在编译时(例如,使用 AspectJ 编译器),加载期或在运行期完成。与其他纯 Java AOP 框架一样,Spring AOP 在运行时执行编织。

Spring AOP 包括以下类型的通知:

  • 前置通知(Before advice):在连接点之前运行但无法阻止执行流程进入连接点的增强(除非它抛出异常)。
  • 后置通知(After returning advice):在连接点正常完成后运行的增强(例如,如果方法返回而不抛出异常)。
  • 异常通知(After throwing advice):如果方法通过抛出异常退出,则执行建议。
  • 最终通知(After (finally) advice):无论连接点退出的方式(正常或异常返回),都要执行建议。
  • 环绕通知(Around advice):围绕连接点的增强,例如方法调用。这是最强大的建议。Around 通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续执行连接点还是通过返回自己的返回值或抛出异常来终止被增强方法的执行。

环绕通知是最通用的通知。由于 Spring AOP(如 AspectJ)提供了全方位的通知类型,因此我们建议您使用可以实现所需行为的影响范围最小的通知类型。

例如,如果您只需要使用方法的返回值更新缓存,那么最好实现后置通知而不是环绕通知,尽管环绕通知可以完成同样的事情。

使用最具体的建议类型可以提供更简单的编程模型,减少错误的可能性。例如,您不需要在用于环绕通知的 JoinPoint 上调用 proceed() 方法,因此,您不会忘记调用它。

所有通知参数都是静态类型的,因此您可以使用相应类型的通知参数(例如,方法执行的返回值的类型)而不是 Object 数组。

由切入点匹配的连接点的概念是 AOP 的关键,它将其与仅提供拦截的旧技术区分开来。切入点使得通知可以独立于面向对象的层次结构进行定向。例如,您可以将一个提供声明性事务管理的通知应用于跨多个对象的一组方法(例如服务层中的所有业务操作)。

Spring AOP 的功能和目标

Spring AOP 是用纯 Java 实现的。不需要特殊的编译过程。Spring AOP 不需要控制类加载器层次结构,因此适合在 servlet 容器或应用程序服务器中使用。

Spring AOP 目前仅支持方法执行连接点(建议在 Spring bean 上执行方法)。虽然可以在不破坏核心 Spring AOP API 的情况下添加对字段拦截的支持,但未实现字段拦截。如果您需要建议字段访问和更新连接点,请考虑使用 AspectJ 等语言。

Spring AOP 的 AOP 方法与大多数其他 AOP 框架的方法不同。目的不是提供最完整的 AOP 实现(尽管 Spring AOP 非常强大)。相反,目标是在 AOP 实现和 Spring IoC 之间提供紧密集成,以帮助解决企业应用程序中的常见问题。

因此,例如,Spring Framework 的 AOP 功能通常与 Spring IoC 容器一起使用。通过使用普通 bean 定义语法来配置切面。这是与其他 AOP 实现的重要区别。

AOP 代理

Spring AOP 默认使用 AOP 代理的标准 JDK 动态代理。这使得任何接口(或接口集)都可以被代理。

Spring AOP 也可以使用 CGLIB 代理。这是代理类而不是接口所必需的。默认情况下,如果业务对象未实现接口,则使用 CGLIB。

由于优化的做法是编程接口而不是类,业务类通常实现一个或多个业务接口。可以强制使用 CGLIB,在那些需要建议未在接口上声明的方法或需要将代理对象作为具体类型传递给方法的情况下(希望很少见)。

掌握 Spring AOP 是基于代理的这一事实非常重要

代理机制

Spring AOP 使用 JDK 动态代理或 CGLIB 为给定目标对象创建代理。JDK 动态代理内置在 JDK 中,而 CGLIB 是一个常见的开源库。

如果要代理的目标对象实现至少一个接口,则使用 JDK 动态代理。目标类型实现的所有接口都是代理的。如果目标对象未实现任何接口,则会创建 CGLIB 代理。

如果要强制使用 CGLIB 代理(例如,代理为目标对象定义的每个方法,而不仅仅是那些由其接口实现的方法),您可以这样做。但是,您应该考虑以下问题:

  • 使用 CGLIB 时,final 方法无法被增强,因为它们无法在运行时生成的子类中重写。
  • 从 Spring 4.0 开始,代理对象的构造函数不再被调用两次,因为 CGLIB 代理实例是通过 Objenesis 创建的。只有当您的 JVM 不允许构造函数绕过时,您才会看到 Spring 的 AOP 支持中的双重调用和相应的调试日志条目。

要强制使用 CGLIB 代理,请将元素 proxy-target-class 属性的值设置<aop:config>true,如下所示:

<aop:config proxy-target-class="true">
    <!-- other beans defined here... -->
</aop:config>

要在使用 @AspectJ 自动代理支持时强制 CGLIB 代理,请将元素的 proxy-target-class 属性设置 <aop:aspectj-autoproxy>true,如下所示:

<aop:aspectj-autoproxy proxy-target-class="true"/>

参考文献

(正文完)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 前言 只有光头才能变强 上一篇已经讲解了Spring IOC知识点一网打尽!,这篇主要是讲解Spring的AOP模...
    Java3y阅读 6,878评论 8 181
  • **** AOP 面向切面编程 底层原理 代理!!! 今天AOP课程1、 Spring 传统 AOP2、 Spri...
    luweicheng24阅读 1,351评论 0 1
  • 本章内容: 面向切面编程的基本原理 通过POJO创建切面 使用@AspectJ注解 为AspectJ切面注入依赖 ...
    谢随安阅读 3,122评论 0 9
  • 周末家庭日 2018.5.26 星期六 天气晴 早上,小月亮说肚子饿,明明有吃了几个水饺,一杯酸奶,几口馒头,她...
    洪一念阅读 226评论 0 0
  • Android 使用任务(Task)来管理活动,一个任务就是一组存放在栈里的活动的集合,后进先出。 一、活动状态 ...
    TTTqiu阅读 1,971评论 1 0