结合项目对AOP的实践和理论讲解-AOP八股
1. 什么是 AOP?
AOP(Aspect-oriented Programming,面向切面编程)是一种设计思想,旨在通过切面技术为业务主体添加额外的通知(Advice),对声明为“切点”(Pointcut)的代码块进行统一管理和装饰。
- 它是对面向对象编程(OOP)的补充:OOP的核心是类(class),AOP的核心是切面(Aspect)。
- 适用场景:将与核心业务关联较弱的通用功能(如日志、权限校验、性能监控等)抽离并统一实现,降低代码耦合度,提高可重用性。
- 简单理解:在方法执行前、执行后、异常时等时机插入通用操作,且不影响原业务逻辑的运行(如技术派中通过AOP记录接口调用耗时)。
2. AOP 的核心概念?
文档中明确提到AOP的5个关键术语:
- 横切关注点:从多个方法中抽取的同一类非核心业务(如所有接口的日志记录)。
- 切面(Aspect):对横切关注点的封装类,通常用
@Aspect
注解定义(如技术派中的MdcAspect
类)。 - 通知(Advice):切面要完成的具体工作,包括5种类型(文档中详细列举):
@Before
:目标方法执行前执行@After
:目标方法执行后执行@AfterReturning
:目标方法返回后执行@AfterThrowing
:目标方法抛出异常后执行@Around
:包裹目标方法,在其执行前后分别执行
- 连接点(JoinPoint):通知应用的时机(如接口方法被调用时)。
- 切点(Pointcut):通知的应用范围,通过切点表达式定义(如技术派中“所有被
@MdcDot
注解的方法”)。
3. AOP 有哪些环绕方式?
即通知的5种类型(文档中“通知”部分明确说明):
@Before
:前置通知,目标方法执行前触发。@After
:后置通知,目标方法执行后(无论是否异常)触发。@AfterReturning
:返回后通知,目标方法正常返回后触发。@AfterThrowing
:异常通知,目标方法抛出异常后触发。@Around
:环绕通知,完全包裹目标方法,可在其执行前后、返回值或异常时自定义逻辑(技术派的MdcAspect
中使用@Around
记录方法耗时)。
4. 平时怎么使用 AOP?
结合文档中技术派的实践,常见用法如下:
- 日志记录:通过AOP拦截接口方法,记录调用参数、返回值、执行耗时等(如
MdcAspect
记录接口耗时并生成traceId
)。 - 统一上下文管理:利用
MDC
(映射诊断上下文)在多线程环境中传递traceId
,便于分布式系统追踪请求链路。 - 动态功能增强:如技术派中通过
@MdcDot
注解标记需要监控的方法,AOP自动为其添加耗时统计和日志输出,无需修改原业务代码。
5. Spring AOP 和 AspectJ AOP 的区别?
- 实现方式:
- Spring AOP 基于动态代理(JDK动态代理或CGLIB)实现,运行时生成代理对象,仅支持方法级别的切点。
- AspectJ 是独立的AOP框架,基于编译期织入(编译时修改字节码)或类加载期织入,支持字段、构造器、方法等更细粒度的切点。
- 依赖:
- Spring AOP 是Spring框架的一部分,无需额外依赖(但使用
@Aspect
需引入AspectJ的注解包)。 - AspectJ 需要单独引入依赖,且功能更全面。
- Spring AOP 是Spring框架的一部分,无需额外依赖(但使用
- 适用场景:
- Spring AOP 适合简单的方法级切面(如日志、权限),与Spring生态无缝集成(技术派中使用的是Spring AOP)。
- AspectJ 适合复杂场景(如字段拦截),但配置和学习成本更高。
6. JDK 动态代理和 CGLIB 代理?
两者是Spring AOP实现动态代理的两种方式:
- JDK 动态代理:
- 基于接口实现,只能代理实现了接口的类。
- 原理:通过
java.lang.reflect.Proxy
生成代理类,代理类实现目标接口,并重写方法,织入增强逻辑。
- CGLIB 代理:
- 基于继承实现,可代理未实现接口的类(通过生成目标类的子类)。
- 原理:通过字节码技术生成目标类的子类,重写父类方法,织入增强逻辑。
- 技术派中,Spring AOP默认优先使用JDK动态代理;若目标类未实现接口,则自动切换为CGLIB代理。
通过技术派的实践可以看出,AOP的核心价值在于“解耦”——将通用功能与业务逻辑分离,既保证代码简洁,又便于统一维护。