SpringFramework — AOP 面试

小龙 584 2022-06-14

AOP 面试题总结

基础与概念

AOP 概述

AOP 面向切面编程,全称 Aspect Oriented Programming,它是对 OOP 技术的补充。OOP 关注的核心是对象,AOP 的核心是切面(Aspect)。AOP 可以再不修改功能代码的前提下,使用运行时动态代理技术对已有的代码逻辑增强。AOP 可以实现组件化、可插拔式的功能扩展,通过简单的配置可以将功能增强到指定的切入点。

AOP 的设计原理

AOP 的底层设计是由运行时动态代理支撑,在 bean 的初始化流程中,借助 BeanPostProcessor 将原始的目标对象织入通知,生成代理对象。

OR
AOP 的设计原理是对原有业务逻辑的横切增强,使用不同的通知方式,它有不同的底层原理支持(编译期、类加载器、对象创建期)

JDK 动态代理和 Cglib 动态代理对比

  • JDK 动态代理要求被代理对象所属类至少实现一个接口,它是 JDK 内置的机制
  • Cglib 动态代理没有接口限制,使用字节码增强技术实现,需要依赖第三方依赖包
  • JDK 动态代理的代理对象创建速度快,执行速度慢;Cglib 动态代理的代理对象创建速度慢,执行速度快。

AOP 的术语

  • Target 目标对象:被代理的原始对象
  • Proxy 代理对象:目标对象被织入通知后产生的对象就是代理对象
  • JoinPoint 连接点:目标对象所属类中定义的所有方法均为连接点
  • Pointcut 切入点:被切面拦截 / 增强的连接点(切入点一定是连接点,连接点不一定是切入点)
  • Advice 通知:增强的逻辑 / 代码,也就是拦截到目标对象的连接点之后要做的事
  • Aspect 切面:切入点 + 通知
  • Weaving 织入:将通知应用到目标对象,进而生成代理对象的过程动作
  • Introduction 引介:特殊的通知类型,可以不修改原有代码的前提下,在运行期间为原始类动态的添加新的属性 / 方法

AspectJ定义的通知类型

  • Before 前置通知:目标对象的方法调用后触发
  • After 后置通知:目标对象的方法调用只会触发
  • AfterRunning 返回通知:目的对的方法调用完成,在返回结果之前触发
  • AfterThrowing 异常通知:目标对象的方法中抛出 / 触发异常后触发
  • Around 环绕通知:编程式控制目标对象的方法调用。环绕通知式所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法前后搞事情,甚至不执行目标对象的方法

这些通知类型中 AfterRunning 和 AfterThrowing 两者是互斥的!如果方法调用成功无异常抛出,则会有返回值;如果方法抛出了异常,则不会有返回值。

AOP 联盟定义的通知类型

  • 前置通知 MethodBeforeAdvice
  • 后置通知(返回通知) AfterRunningAdvice
  • 异常通知 ThrowsAdvice
  • 环绕通知 MethodInterceptor
  • 引介通知 IntroductionAdvice

AOP 的编码与应用

AOP 使用场景

AOP 的使用范围是非常的广的

  • 业务日志切面:可以记录业务方法的调用痕迹
  • 事务控制:通过切面可以实现声明式事务控制
  • 权限校验:执行方法之前先校验当前登陆用户是否用于相应权限
  • 数据缓存:执行方法之前先从缓存中获取,取到则直接返回,不走业务方法;没取到执行业务方法,拿到数据后在方法返回之前,将数据缓存

多个切面的执行顺序如何控制

  • 显示使用 @Order 注解,或者 Ordered 接口,声明切面的执行顺序(默认Integer.MAX_VALUE)
  • 通过使用类名的 unicode 编码排序,控制切面的执行顺序

AOP 的失效场景

  • 代理对象使用 this 调用自身的方法时,AOP通知会失效
    • 正确的做法是借助 AopContext 取到当前代理对象并强转,之后调用,这样 AOP 通知依然会执行
  • 代理对象在后置处理器还没初始化的时候,提前创建了,则 AOP 通知不会织入
    • 由于 AOP 是借助 BeanPostProcessor 实现的,如果 BeanPostProcessor 还没初始化好,目标对象就已经创建了,则不可能在生成代理对象

# AOP # 面试