面向切面编程的基本原理
DI有助于应用对象之间的解耦,而AOP可以实现横切关注点与他们所影响对象之间的解耦。
1.什么是面向切面编程
切面能够帮助我们模块化横切关注点。横切关注点可以被描述为影响应用多处的功能。安全就是一个横切关注点
定义AOP术语
通知:定义了切面是什么,以及何时使用,除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题,他应该用在某个方法被调用之前/之后/之前之后都调用,还是方法抛出异常时调用
Spring切面可以应用5钟类型的通知
- 前置通知
- 后置通知
- 返回通知
- 异常通知
- 环绕通知
连接点——连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
切点——一个切面并不需要通知应用的所有连接点。切点有助于缩小切面所通知的连接点的范围。
通知定义了切面的“什么”和“何时”的话,那么切点就定义了“何处”。
切面——是通知和切点的结合.通知和切面共同定义了切面的全部内容——它是什么,它在何时和何处完成其功能。
引入——允许我们向现有的类添加新的方法或属性;创建一个通知类该类记录了对象最后一次的修改状态,需要一个方法和一个实例变量来保存这个状态。然后这个新方法和新实例变量就可以引入到现有类中,从而无需修改这些现有类的情况下,让他们具有新的行为和状态。
织入——把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的声明周期里有多个点可以进行织入。
Spring提供了4种类型的AOP支持
- 基于代理的经典SpringAOP
- 纯POJO切面
- @AspectJ注解驱动的切面;
- 注入式AspectJ切面(适用于Spring各版本)
前三种都是AOP实现的变体,SpringAOP构建在动态代理的基础之上,因此,Spring对AOP的支持局限于方法的拦截
Spring在运行时通知对象
通过在代理类中包裹对象,Spring在运行期间把切面织入到Spring管理的Bean中。代理类封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean。当代理拦截到方法调用时,在调用目标Bean方法之前,会执行切面逻辑。
直到应用需要被代理的bean时,Spring才创建代理对象。如果使用 的是ApplicationContext的话,在ApplicationContext从BeanFactory中加载所有bean的时候,Spring才会创建被代理的对象。因为Spring运行时才创建代理对象,所以我们不需要特殊的编译器来织入AOP的切面。
Spring只支持方法级别的连接点
通过各种AOP方案可以支持多种连接点模型。因为Spring基于动态代理,所以Spring只支持方法连接点。
通过切点来选择连接点
在SpringAOP中,要是用AspectJ的切点表达式语言来定义切点。
SpringAOP 所支持的AspectJ切点指示器
我们注意到只有execution指示器是实际执行匹配的,而其他的指示器都是用来显示匹配的。execution指示器是我们在编写切点定义时最主要使用的指示器。
编写切点
为了阐述Spring中的切面,我们需要有个主题来定义切面的切点。
定义切点表达式
使用注解创建切面
AspectJ提供了无个注解来定义通知
如果你就此止步的话,Audience只会是Spring容器中的一个bean,即便使用了AspectJ注解它也不会被视为切面,这些注解不会解析,也不会创建其转换为切面的代理。
创建环绕通知
处理通知中的参数