Spring AOP 支持哪两种动态代理方式?

Spring AOP 支持以下两种动态代理方式:

  1. JDK 动态代理 (JDK Dynamic Proxy)
  2. CGLIB 代理 (Code Generation Library)

Spring 框架会根据你的业务对象(目标对象)的情况,智能地选择其中一种来创建代理。


1. JDK 动态代理

  • 技术基础:Java 官方提供的 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口,是 Java 原生支持的。
  • 实现方式:在运行时,创建一个新的代理类,这个代理类会实现目标对象所实现的所有接口
  • 硬性要求被代理的目标对象必须实现至少一个接口。 如果一个类没有实现任何接口,JDK 动态代理就无法为其创建代理。
  • 工作流程:当你调用代理对象的方法时,这个调用会被转发到 InvocationHandlerinvoke() 方法中。Spring AOP 在 invoke() 方法内部织入了你的切面逻辑(如 @Before@After 等),然后再通过 Java 的反射机制调用原始目标对象的方法。

2. CGLIB 代理

  • 技术基础:一个强大的第三方代码生成库(Spring 内部集成了它),它通过字节码增强 (Bytecode Enhancement) 技术来工作。
  • 实现方式:在运行时,动态地创建一个被代理对象的子类作为代理对象。
  • 硬性要求被代理的目标类不能是 final 类,需要被代理的方法也不能是 finalprivate,因为子类无法继承 final 类或重写 final/private 方法。
  • 工作流程:代理类会重写(Override)父类(即你的目标对象)中所有非 final 的方法。在这些重写的方法里,Spring AOP 织入了切面逻辑,然后再通过调用 super.method() 来执行原始目标对象的业务逻辑。

Spring 如何选择?

这是面试中的高频问题,因为这个默认行为在不同版本中有所变化。

场景Spring 的选择
目标对象实现了接口老的 Spring 版本传统 Spring XML 配置中,默认使用 JDK 动态代理

Spring Boot (2.x 及以后) 中,为了统一行为和解决一些代理问题,默认依然使用 CGLIB
目标对象没有实现接口无论在哪个版本,都只能使用 CGLIB

为什么 Spring Boot 默认使用 CGLIB?
主要原因是为了解决“方法自调用时 AOP 失效”的问题,并提供更一致的行为。使用 CGLIB 可以确保即使目标对象实现了接口,代理的也是类本身,这在处理一些复杂的依赖注入和内部调用场景时更加可靠。

当然,你也可以通过在 application.properties 中进行配置来改变这个默认行为:

# 如果设置为 true (默认值),则统一使用 CGLIB
# 如果设置为 false,则在目标对象实现接口时,会优先使用 JDK 动态代理
spring.aop.proxy-target-class=true 

总结对比

特性JDK 动态代理CGLIB 代理
代理方式基于接口 (实现共同接口)基于继承 (创建子类)
前提条件目标对象必须实现接口目标对象不能是 final 类
性能在早期版本中,通过反射调用性能略低于 CGLIB。但在目前JDK 版本中,两者性能差距已经非常小。性能通常被认为略高,因为它直接操作字节码并调用 super
Spring Boot 默认
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值