Spring AOP 原理
AOP 即面向切面编程(Aspect Oriented Programing),实际上是将一些通用的功能横向抽取出来:
- 一方面,减少系统的重复代码
- 另一方面,降低模块间的耦合度,比较好维护和扩展
Spring AOP 将应用分为核心关注点和横切关注点。业务处理流程为核心关注点,被业务所依赖的公共部分为横切关注点。横切关注点的特点是其行为经常发生在核心关注点多出,而多处操作基本相似,比如权限认证、日志、事务等。AOP 的核心思想是将核心关注点和横切关注点分离开来,以降低模块耦合度。
Spring AOP 的应用场景主要有:
- 权限统一管理授权
- 缓存统一维护
- 数据懒加载
- 资源池统一申请和管理
- 统一事务管理
AOP 相关术语
术语 | 解释 | 描述 |
---|---|---|
Joinpoint | 连接点 | 所谓连接点是指那些被拦截到的点。在 Spring 中,这些点指的是方法,因为 Spring 只支持方法类型的连接点。 |
Pointcut | 切入点 | 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。 |
Advice | 通知/增强 | 所谓通知是指拦截到 Joinpoint 之后要执行的具体操作。通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能) |
Introduction | 引介 | 引介是一种特殊的通知。在不修改类代码的前提下,可以在运行期为类动态地添加一些方法或字段 |
Target | 目标对象 | 代理的目标对象 |
Weaving | 织入 | 是指把增强应用到目标对象来创建新的代理对象的过程。 有三种织入方式:Spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入 |
Proxy | 代理 | 一个类被 AOP 织入增强后,就产生一个结果代理类 |
Aspect | 切面 | 是切入点和通知(/引介)的结合 |
例如在 IUserDao 接口中:
1 | public interface IUserDao { |
- IUserDao 被增强的对象,就是 Target(目标对象)
- add()、delete()、update() 和 search() 都是 JoinPoint(连接点)
- 这里要对 add() 和 update() JoinPoint 进行拦截,则 add() 和 update() 就是 Pointcut(切入点)
- Advice 指的是要增强的代码,也就是代码的增强
- Weaving:指的是把增强(Advice)应用到目标对象(Target)创建新的代理对象的过程
- Aspect:是切入点和通知的结合,在 add 或 update 方法上应用增强
AOP 底层原理
AOP 的底层原理是动态代理机制:
- 类实现了接口,JDK 动态代理
- 类未实现任何接口,Cglib 动态代理
AOP 的 5 种通知类型
前置通知
在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常。
后置通知
在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容。
成功通知
在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行。
异常通知
在连接点抛出异常后执行。
环绕通知
环绕通知围绕在连接点前后,比如一个方法调用的前后。这是最强大的通知类型,能在方法调用前后自定义一些操作。环绕通知还需要负责决定是继续处理连接点(调用ProceedingJoinPoint 的 proceed 方法)还是中断执行。
五种通知的执行顺序为:前置通知、环绕通知、成功通知/异常通知、后置通知。
Spring AOP & AspectJ AOP
增强时机
Spring AOP 是运行时增强;AspectJ 是编译时增强
底层原理
Spring AOP 基于代理;AspectJ 基于字节码操作 (Bytecode Manipulation)
性能
AspectJ 相比于 Spring AOP 功能更加强大,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。Spring AOP 相对来说更简单,并且 Spring AOP 已集成了 AspectJ,如果切面较少,那么两者性能差异不大,当切面较多时,最好选择 AspectJ ,它比 Spring AOP 快很多。