AOP代理
1、什么是 AOP?
AOP,又称面向切面编程,AOP 是一种编程思想,是面向对象编程的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程将程序抽象成各个层次的切面。
在面向切面的编程思想里面,把功能分为核心业务功能和周边功能。
- 核心业务:比如登录,删除数据,增加数据。
- 周边功能:比如性能统计,日志,事务管理等。
周边功能在 spring 的面向切面编程 AOP 思想里,即被定义为切面。
在面向切面编程 AOP 的思想里面,核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能 “编织” 在一起,这就叫 AOP
2、为什么需要 AOP?
AOP 可以将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于将来的可扩展性和可维护性。
AOP 要实现的效果是,保证开发者在不修改源代码的前提下,去为系统中的业务组件添加某种通用的功能。
AOP 的本质是由 AOP 框架修改业务组件的多个方法的源代码,就是代理模式的典型应用。
3、实现分类?
- 静态 AOP 实现,AOP 在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类,如 Aspectj。
- 动态 AOP 实现,AOP 框架在运行阶段动态生成代理对象(在内存中以 JDK 动态代理,或 CGLib 动态的生成 AOP 代理类),如 Spring AOP。
比较:
类别 | 机制 | 原理 | 优点 | 缺点 |
---|---|---|---|---|
静态 AOP | 静态织入 | 在编译时,切面直接以字节码的形式编译进目标子节码文件中 | 对系统无性能影响 | 灵活性不够 |
动态 AOP | JDK 动态代理 | 在运行期,目标类加载后,为接口动态生成代理类,将切面织入到代理类中 | 相对于静态 AOP 更加灵活 | 切入的关注点需要实现接口,对系统有一点性能影响 |
动态子节码 | CGLib | 在运行期,目标类加载前,动态生成目标类的子类,将切面逻辑加入到子类中 | 没有接口也可以织入 | 扩展类的实例,方法用 final 修饰时则无法织入 |
自定义类加载器 | 在运行期,目标类加载前,将切面逻辑加入到目标字节码里 | 可以对绝大部分类进行织入 | 代码中如果使用了其他类加载器,则这些类不会织入 | |
字节码转换 | 在运行期,所有类加载器加载字节码前进行拦截 | 可以对所有类进行织入 |
4、概念
AOP 增强
- Aspect(切面):通常是一个类,里面可以定义切入点和通知,切面是通知和切入点的结合。在什么时机,什么地方,做什么增强!
- Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式。在哪些类,哪些方法上切入。
- Advice(通知):AOP 在特定的切入点上执行的增强处理。通知描述了切面何时执行以及如何执行增强处理。在方法执行的什么时机,做什么。
- JointPoint(连接点):连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
- Weaving(织入):将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。
通知
- 前置通知:在我们执行目标方法之前运行(@Before)。
- 后置通知:在我们目标方法运行结束之后 ,不管有没有异常**(@After)。**
- 返回通知:在我们的目标方法正常返回值后运行**(@AfterReturning)。**
- 异常通知:在我们的目标方法出现异常后运行**(@AfterThrowing)。**
- 环绕通知:动态代理, 需要手动执行 joinPoint.procced()(其实就是执行我们的目标方法执行之前相当于前置通知, 执行之后就相当于我们后置通知**(@Around)。**环绕通知可用来做权限验证。
5、执行顺序
在 springboot 中可以通过 Order 指定执行的顺序,around 与 before 比 order 小,around 与 after、afterreturning、afterthrowing 比 order 大。
异常情况下,环绕通知的后通知,返回通知会被异常通知阻断,不会执行。