1 AOP 简介
面向切面编程(Aspect-Oriented Programming, AOP)通过提供一种思考程序结构的途经,来弥补面向对象编程(Object Oriented Programming, OOP)的不足。在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的单元中切面。切面能对关注点进行模块化,例如横切多个类型和对象的事务管理。在 AOP 术语中通常称为横切关注点。
AOP 框架作为 Spring 的核心组件,主要被用来:
- 提供声明式企业服务,尤其是作为 EJB 的更好替换者。最重要的服务就是声明式事务。
- 允许用户实现自定义的切面,通过 AOP 的方式完成它们对 OOP 的使用。
2 AOP 概念
-
横切关注点
- 简单地理解就是那些与实际业务操作无关,但是又需要嵌入到多个类型或对象中以完善系统功能的重复代码,最常见的有:日志记录、事务管理等。 切面(Aspect)
- 是指需要实现的交叉功能,如日志记录切面。在实现上,其实就是将横切关注点进行模块化处理后得到的类,也就是切面类。切面类中通常包含了切点和通知。 连接点(JoinPoint)
- 应用程序在执行过程中可以插入切面的点。常见的连接点可以是方法执行、异常抛出,甚至修改字段。在 Spring AOP 中,连接点永远代表方法执行。 通知(Advice)
-
在指定的连接点切入执行的动作,即切面的实际实现。主要的通知类型有:
Before advice
,After returning advice
,After throwing advice
,After(finally) advice
,和Around advice
。
切入点(Pointcut)
- 一个匹配连接点的术语,它定义了通知应该应用在哪些连接点。通常通过指定类名和方法名,或者匹配类名和方法的正则表达式来指定切入点。 引入(Introduction)
- 在已存在的类中添加新方法和属性。 目标对象(Target Object)
- 被一个或多个切面通知的对象。如果没有 AOP,这个类必须包含它的主要逻辑以及其他交叉业务逻辑;有了 AOP,目标对象就可以完全地关注主要业务,不再关注应用其上的通知。由于 Spring AOP 是通过运行时代理实现的,所以,目标对象将永远是一个被代理对象。 AOP 代理(AOP proxy)
- 由 Spring AOP 框架创建的,将通知应用到目标对象后的对象。在 Spring AOP 中,代理对象要么是 JDK 动态代理,要么是 CGLIB 代理。 织入(Weaving)
- 将切面应用到目标对象来创建的代理对象过程。织入的过程可以是在编译期(这种方式需要特殊编译器,AspectJ 的织入编译器就是以这种方式织入切面)、加载期或者运行期(Spring AOP 就是在此时期织入切面的)。
总结:
以具体的 Spring AOP 实现为例,面向切面就是在目标对象的基础上,在运行期织入一些与实际业务逻辑无关的操作,由 Spring 产生织入后目标对象的代理对象,通过代理对象来完成完整的功能。其中,在目标对象上织入的即为切面,包括:
- 切点:具体切入到目标对象的什么地方,如方法调用、异常抛出等。
- 通知:具体在目标对象上织入了什么内容,添加了哪些操作;在什么时间织入,如方法调用前,抛出异常后等。
关于连接点和切入点:连接点是对程序中所有能够插入切面的点的统一描述,切入点才是真正插入切面的地方,所以,切入点是连接点的子集。
3 AOP 的实现
AOP 的实现众多,也都很优秀,各有所长,Spring 主要支持如下两种:
- Spring AOP:纯 Java 实现,不需要专用的编译过程和特殊的类装载器,在运行期通过代理方式向目标织入增强代码。对于 Spring 1.2 及之前的早期版本使用的就是此方式,但在高版本中虽然兼容,已经不再推荐。
- AspectJ:扩展了 Java 语言,定义了 AOP 语法,能够在编译期提供横切代码的织入,所以它有一个专门的编译器用来生成遵守 Java 字节编码规范的 class 文件。Spring 的高版本已经无缝整合了此技术,并且随着注解的引入,AspectJ 就有基于 xml 配置文件和基于 @Annotation 两种方式,推荐使用。