15.2 AOP(Aspect-Oriented Programming)

    我们在软件设计时,会把系统分割为小的单独的单元来处理,我们把这种设计方法称之为SoC(即Separation of Concerns)——一个关注点(Concern)就是一个问题。编程过程中,我们把这些关注点模块化在编程语言所提供的单元里,例如,在传统的编程语言中(这里指过程式编程/函数式语言),会把系统分割成数据结构和方法,在OOP语言中,我们通常把它们分解为类。

    SoC一方面分解了问题:我们把系统表示为一堆软件和实体之间的交互问题,把复杂的问题按照功能分解成了小粒度的简单问题,主要是纵向分解了问题,然后各个击破。但另一方面,正是由于分解产生了很多小单元,自然而然地出现了一些横跨这些单元的相同逻辑,即在水平方向上出现了相同的逻辑。

    在上述例子中,记录travel()的执行时间和记录celebrate()的执行时间,都是相同的问题。使用传统的软件编程和OOP,我们都不容易解决这种重复问题,例如使用模板方法模式仍然导致在这两个方法分别添加相同逻辑的代码。为了把这种水平方向上的逻辑进行模块化,随之便产生了AOP编程。

    AOP可以在水平方向上补充OOP的这一缺点,它可以把这些离散的、跨模块的、混入其他关注点的逻辑放在一个独立的模块里,即从横向模块化了问题。比如,对于上述计时问题,我们可以把记录这些方法执行时间的逻辑模块化在同一个单元里,这个新的模块化单元就称之为切面(Aspect)。

    编程过程中有很多“水平”问题,例如事务管理、异常处理、日志记录、安全管理、性能优化、透明的持久化等,这些问题也是J2EE关注的重要问题,由于AOP在这方面发挥出色,AOP也成了时下很多J2EE流行框架的重要部分。

    下面我们就从一些基础概念入手了解AOP。

    15.2.1 一些重要概念

    下面我们先介绍一些AOP的重要概念和术语。

    1.切面(Aspect)

    横切关注点(Concerns)模块化后称为切面。在传统的软件编程方法里,我们把关注点模块化为函数、过程、类等,而在AOP编程里,我们把关注点模块化为切面。

    2.连接点(Joinpoint)

    程序执行过程中可被识别的某个点叫做连接点。连接点可以是某个方法的调用,也可以是某个赋值操作,是AOP里最基础的概念。例如上例中travel()方法调用onTravel()方法的位置就是一个连接点。

    3.增强(Advice,有时也翻译为通知)

    连接点处执行的逻辑叫做增强。分为前增强、后增强、环绕增强、异常增强和最终增强。

    前增强(Before advice):在连接点之前执行的增强。

    后增强(After returning advice):在连接点正常执行完成后执行的增强。

    异常增强(After throwing advice):捕捉连接点抛出特定异常后执行的增强。

    最终增强(After/finally advice):调用连接点之后始终执行的增强,不管此连接点是异常退出还是正常退出。

    环绕增强(Around Advice):包围一个连接点的增强。它控制连接点的执行,是最强大的一种增强,它在连接点之前和之后都完成一些操作,负责调用连接点,甚至可以不执行连接点,直接抛出异常。

    4.切入点(Pointcut)

    某些特定连接点(Joinpoint)的逻辑叫做切入点。根据切入点我们可以判断哪些连接点(Joinpoint)需要增强,哪些不需要。

    5.织入(Weaving)

    把这些水平的切面连接到执行过程以组合成完整流程的行为称之为织入。织入可以发生在编辑期、编译期、类加载期和运行期。