spring aop默认自动选择代理方式:目标类实现接口时用jdk动态代理,否则用cglib;可通过@enableaspectjautoproxy(proxytargetclass = true)强制启用cglib。

Spring AOP 的核心原理是基于代理(Proxy)机制,在不修改原始类代码的前提下,为方法调用“织入”横切逻辑(如日志、事务、权限校验等)。它本身不直接操作字节码,而是依托 Java 的动态代理技术,在运行时生成代理对象,拦截目标方法执行流程。
Spring AOP 默认使用 JDK 动态代理还是 CGLIB?
Spring 会自动选择:
- 如果目标类实现了至少一个接口,默认用 JDK 动态代理(基于
java.lang.reflect.Proxy),代理接口类型; - 如果目标类没有实现任何接口,则强制使用 CGLIB 代理(通过字节码增强生成子类);
- 你也可以通过
@EnableAspectJAutoProxy(proxyTargetClass = true)强制启用 CGLIB,哪怕有接口也走子类代理。
JDK 动态代理是怎么工作的?
它依赖三个关键角色:
- 目标对象:原始业务类(必须实现接口);
-
InvocationHandler:统一拦截逻辑的处理器,所有代理方法调用最终都落到它的
invoke()方法; - Proxy.newProxyInstance():根据类加载器、接口列表和 handler 创建代理实例。
Spring 内部将切面(@Aspect)、切入点(@Pointcut)和通知(@Before/@After 等)组装成一个 ReflectiveMethodInvocation 链,由 DefaultAopProxyFactory 封装进 JDK 的 InvocationHandler 中。
CGLIB 代理的关键特点
CGLIB 不依赖接口,而是通过继承目标类生成子类(重写非 final 方法),因此:
- 目标类不能是
final,方法也不能是final或private(否则无法被子类覆盖); - 需要额外引入
cglib-nodep(Spring 5.0+ 已内置,无需手动添加); - 性能略高于 JDK 代理(尤其在大量代理场景),但启动稍慢(需生成字节码)。
通知执行顺序与增强链(Advice Chain)
多个通知(如 @Before + @Around + @AfterReturning)不是简单串行,而是按责任链模式组织:
-
@Around可以控制是否执行目标方法(用proceed()); -
@Before在目标方法前执行,@After在之后(无论是否异常); -
@AfterReturning仅在正常返回后触发,@AfterThrowing仅在抛异常后触发; - 同类型通知可通过
@Order或实现Ordered接口指定优先级。
Spring 把这些通知包装成 Advisor,再由 AdvisedSupport 统一管理并构建调用链。
基本上就这些。理解代理选型、拦截入口和通知生命周期,就能稳住 Spring AOP 的主干逻辑。实际开发中,多数问题出在代理失效(比如自调用、非 public 方法、final 类)——这些都不是 bug,而是代理机制本身的边界。











