在软件开发中,散步在应用程序中多处的功能被称为横切关注点(cross-cutting concern)。通常来讲这些横切关注点从概念上讲是与业务逻辑相分离的。把这些横切关注点与业务逻辑分离正是面向切面编程(AOP)要做的事。
1.什么是面向切面编程
切面能够帮助我们模块化横切关注点。横切关注点可以被描述为影响应用多处的功能。下图展现了被划分为模块的经典应用,每个模块都有特定的业务逻辑,但这些模块都需要特定的辅助功能,如日志、缓存和事务管理。
面向切面编程提供了实现重用通用功能很好的方案。在使用面向切面编程时,我们仍然在一个地方定义通用功能,但是可以通过声明的方式定义这个功能以何种方式在何处使用,而无需修改受影响的类。横切关注点可以被模块化为固定的类,这些类称为切面(aspect)。这样做有两个好处:首先每个关注点都集中于一个地方,而不是分散在代码各处;其次,服务模块更简洁,因为他们只包含关注点(或核心功能)的代码,其次要关注点的代码被转移到切面中了。
1.1定义AOP的术语
与大多数技术一样AOP已经形成了自己的术语。描述切面术语有通知(advice)、切点(pointcut)和连接点(joinpoint)。
通知(Advice)
在AOP术语中,切面的工作被称为通知。通知定义了切面是什么以及何时调用。Spring切面可以应用5中类型的通知:
通知类型 | 描述 |
---|---|
前置通知(Before) | 在目标方法调用前调用通知 |
后置通知(After) | 在目标方法调用后调用通知 |
返回通知(After-returning) | 在目标方法成功执行之后调用通知 |
异常通知(After-throwing) | 在目标方法发生异常时调用通知 |
环绕通知(Around) | 通知包裹目标方法,在被通知的方法调用之前和调用之后执行自定义的行为 |
连接点(Join point)
我们的应用程序可能有数以万计的时机应用通知,这些时机被称为连接点。连接点是应用程序执行过程中能够插入切面的一个点。这个点可以是调用方法、抛出异常、甚至修改一个字段时。切面代码利用这些切入点插入到正常的流程中,并添加新的行为。
切点(Pointcut)
如果说通知定义了“什么”和“何时”的话,那么切点就定义了“何处”,切点的定义会匹配通知所要织入的一个或多个连接点。我们常常使用明确的类和方法的名称,或使用正则表达式定义所匹配的类和方法的名称来匹配连接点。有些AOP框架允许我们创建动态连接点,可以根据运行时的策略(比如方法的参数值)来决定是否应用通知。
切面(Aspect)
切面是通知和切点的结合--他是什么,在何时、何处完成其功能。
引入(Introduction)
引入允许我们向现有的类中添加方法和属性。例如我们创建了一个Auditable通知类,该类记录对象最后以此修改的状态。只需要一个方法setLastModified(Date),和一个实例变量来保存这个状态。然后这个方法和变量就会被引入现有的类中,从而可以在不修改现有类的情况下为他们添加心得方法和状态。
织入(Weaving)
织入就是将切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点织入到目标对象中。在目标对象的生命周期中有多个点可以织入:
编译器:切点在目标对象类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。
运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态的创建一个代理对象。Spring AOP就是以这种方式被织入切面的。
在了解了AOP的这些术语后,就让我们来看看AOP的这些概念在Spring中是如何实现的。
2.Spring对AOP的支持
并不是所有的AOP框架都是相同的,他们在连接点模型上可能有强弱之分。有些允许修饰符级别应用通知,而另一些只支持与方法调用相关的连接点。他们织入切面的方式和时机也有所不同。但无论如何,创建切点来定义切面所织入的连接点是AOP框架的基本功能。
Spring提供了4种类型的AOP支持:
- 基于代理的经典Spring AOP
- 纯POJO切面
- @AspectJ注解驱动的切面
- 注入式AspectJ切面(适用于Spring各版本)
前三种都是Spring AOP实现的变体,Spring AOP构建在动态代理基础之上,因此,Spring 对AOP的支持局限于方法拦截。下面我们来看看Spring AOP框架中一些关键的知识。
2.1Spring通知是Java编写的
Spring所创建的通知都是使用标准的Java类来编写的。这样我们可以使用与普通Java开发一样的集成开发环境(IDE)来开发切面。
2.2Spring在运行时通知对象
Spring是在运行期把切面织入到Spring管理的bean中。代理类封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean。当代理拦截到方法调用时,再调用目标bean方法之前,会执行切面逻辑。直到应用真正需要被代理的bean时,Spring才能创建代理对象。因为Spring运行时才创建代理对象,所以不需要特殊的编译器来织入Spring AOP的切面。
2.3Spring只支持方法级别的连接点
正如前面讲述的,通过使用各种AOP方案可以支持多种连接点模型。但Spring是基于动态代理的,所以Spring只支持方法连接点。这与一些其他的AOP框架是不同的,例如AspectJ和Jboss,除了方法切点,他们还支持字段和构造器接入点。但是方法拦截器可以满足绝大所数需求,如果我们需要使用方法拦截器之外的连接点可以利用Aspect来补充Spring AOP的功能。
对于什么是AOP以及Spring如何支持AOP的,我们现在已经有了一个大致的了解。下节我们将会学习如何在Spring中创建切面,是不是很期待呢!!