文章目录
- 一、面向切面的基本原理
- 二、AOP基础知识
- 三、Spring 对 AOP 的支持
- 四、使用切点选择连接点
- 五、SpringAOP的应用实例
一、面向切面的基本原理
1、什么是面向切面编程
横切关注点:影响应用多处的功能(安全、事务、日志)
2、切面:
横切关注点被模块化为特殊的类,这些类称为切面
3、优点:
每个关注点现在都集中于一处,而不是分散到多处代码中,
相同的逻辑可以统一处理,简化代码,
服务模块更简洁,服务模块只需关注核心代码。
二、AOP基础知识
1、AOP术语:
1. 通知(Advice)
切面的工作被称为通知,通知定义了切面的工作内容是什么以及何时使用。
Spring切面可以应用5种类型是我通知:
1) 前置通知 @Before
在目标方法被调用之前执行。
2) 后置通知 @After
在目标方法被调用之后执行。目标方法正常或异常都执行。
3) 返回通知 @AfterReturning
在目标方法被调用之后执行。目标方法正常结束才执行。
4) 异常通知 @AfterThrowing
在目标方法被调用发生异常之后执行。
5) 环绕通知 @Around
通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
2. 连接点(Joinpoint)
定义:连接点是一个应用执行过程中能够插入一个切面的点。
连接点可以是调用方法时、抛出异常时、甚至修改字段时;
切面代码可以利用这些点插入到应用的正规流程中;
程序执行过程中能够应用通知的所有点。
3. 切点(Pointcut)
定义:如果通知定义了“什么”和“何时”。那么切点就定义了“何处”。切点会匹配通知所要织入的一个或者多个连接点。
通常使用明确的类或者方法来指定这些切点。
作用:定义通知被应用的位置(在哪些连接点)
4. 切面(Aspect)
定义:切面是通知和切点的集合,通知和切点共同定义了切面的全部功能——它是什么,在何时何处完成其功能。
5. 引入(Introduction)
引入允许我们向现有的类中添加方法或属性
6. 织入(Weaving)
织入是将切面应用到目标对象来创建的代理对象过程。
切面在指定的连接点被织入到目标对象中,在目标对象的生命周期中有多个点可以织入
2、AOP过程:
- 编译期
切面在目标类编译时期被织入,这种方式需要特殊编译器。AspectJ的织入编译器就是以这种方式织入切面。 - 类加载期
切面在类加载到JVM ,这种方式需要特殊的类加载器,他可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5 的 LTW 就支持这种织入方式 - 运行期
切面在应用运行期间的某个时刻被织入。一般情况下,在织入切面时候,AOP 容器会为目标对象动态的创建代理对象。Spring AOP 就是以这种方式织入切面。
三、Spring 对 AOP 的支持
并不是所有的 AOP 框架都是一样的,他们在连接点模型上可能有强弱之分。
- 有些允许对字段修饰符级别应用通知;
- 有些支持方法调用连接点;
1、Spring 提供的 4 种各具特色的 AOP 支持
- 基于代理的经典 AOP;
- @AspectJ 注解驱动的切面;
- 纯 POJO 切面;
- 注入式 AspectJ 切面; Spring
2、在运行期间通知对象
通过在代理类中织入包裹切面,Spring 在运行期间将切面织入到 Spring 管理的 Bean 中。
代理类封装了目标类,并拦截被通知的方法调用,再将调用转发给真正的目标 Bean
当拦截到方法调用时,在调用目标 Bean 方法之前,代理会执行切面逻辑。
当真正应用需要被代理的 Bean 时,Spring 才创建代理对象。如果使用 ApplicationContext,在 ApplicationContext 从 BeanFactory 中加载所有 Bean 时,Spring 创建代理对象,因为 Spring 在运行时候创建代理对象,所以我们不需要特殊的编译器来织入 Spring AOP 的切面。
3、Spring 支持方法创建连接点
- 因为 Spring 基于动态代理,所以 Spring 只支持方法连接点。
- Spring 缺失对字段连接点的支持,无法让我们更加细粒度的通知,例如拦截对象字段的修改
- Spring 缺失对构造器连接点支持,无法在 Bean 创建时候进行通知。
四、使用切点选择连接点
切点用于准确定位,确定在什么地方应用切面通知。
Spring 定义切点:在 Spring AOP 中,需要使用 AspectJ 的切点表达式来定义切点。
- 创建自己的切点
- execution( ) 指示器选择 Instrument 的 play( ) 方法。
方法表达式是以 * 号开头,标识了我们不关心的方法返回值的类型。 - 后我们指定了权限定类名和方法名。
对于方法的参数列表,使用(…)标识切点选择任意的 play( ) 方法,无论入参是什么。 - 假设我们需要匹配切点仅匹配 com.Springinaction.springidol 包。可以使用 within()
- 注意 && 是将 execution( ) 和 within( ) 连接起来,形成的 and 关系。同理也可以使用 || 或关系、!非关系
- 创建 Spring 的 bean( ) 指示器
Spring 2.5 引入一个新的 bean( ) 指示器,该指示器允许我们在切点表达式中使用 Bean ID 来标识 Bean
bean( ) 使用 Bean ID 或 Bean 名称作为参数来限制切点只匹配特定 Bean。
如下,我们希望执行 Instrument 的 play( ) 方法时候应用通知,但限定 Bean 的 ID 为 eddie
还可以使用非操作作为除了指定 ID 的 Bean 以外的其他 Bean应用通知;
在此场景下,切面会通知被编织到所有 ID 不为 eddie 的 Bean 中 - 现在几乎不用XML配置了,故在此不再解释XML的APO配置
五、SpringAOP的应用实例
SpringAOP的应用实例及自定义后置处理器