Spring AOP 默认用 JDK 动态代理还是 CGLIB?为什么 @Transactional 自调用会失效?理解代理机制才能避开这些坑。

一、AOP 的核心概念

  • 1.1 Aspect / JoinPoint / Advice / Pointcut / Weaving
  • 1.2 Spring AOP vs AspectJ 的区别
  • 1.3 Spring AOP 是基于代理的——只能拦截方法

二、JDK 动态代理

  • 2.1 基于接口的代理——必须有接口
  • 2.2 Proxy.newProxyInstance() 原理
  • 2.3 InvocationHandler.invoke() 的实现
  • 2.4 生成的代理类长什么样——$Proxy0 反编译

三、CGLIB 动态代理

  • 3.1 基于类的代理——不需要接口
  • 3.2 EnhancerMethodInterceptor
  • 3.3 FastClass 机制——避免反射
  • 3.4 生成的代理类——继承目标类
  • 3.5 final 方法和 final 类的限制

四、Spring 的代理选择策略

  • 4.1 Spring Boot 1.x vs 2.x 的默认策略变化
  • 4.2 spring.aop.proxy-target-class=true 强制使用 CGLIB
  • 4.3 有接口时:JDK 动态代理
  • 4.4 无接口时:CGLIB
  • 4.5 同时有接口又有具体类依赖——@EnableAspectJAutoProxy(proxyTargetClass=true)

五、自调用失效问题

  • 5.1 什么是自调用——类内部方法调用
  • 5.2 失效原因——调用的是 this.method() 而非代理对象
  • 5.3 AopContext.currentProxy() 获取当前代理
  • 5.4 @EnableAspectJAutoProxy(exposeProxy=true) 暴露代理
  • 5.5 另一种解法——把被调方法提取到另一个 Bean

六、AOP 源码核心流程

  • 6.1 @EnableAspectJAutoProxy@Import(AspectJAutoProxyRegistrar)
  • 6.2 AnnotationAwareAspectJAutoProxyCreator——BeanPostProcessor
  • 6.3 postProcessAfterInitialization()wrapIfNecessary()
  • 6.4 代理创建的时机——在 Bean 初始化之后

七、实战案例

  • 7.1 自定义 @Log 注解 + AOP 实现方法日志
  • 7.2 自定义 @RateLimit 注解 + AOP 实现限流

八、总结

  • 性能对比:CGLIB > JDK 动态代理
  • 何时用哪个 + 自调用问题的解决方案