Spring 动态代理与CGLIB

通俗易懂!Spring 动态代理 vs CGLIB 一次讲透(2025 面试必考,画图+口诀,背完直接秒杀)

一句话记住区别:

  • JDK 动态代理:必须实现接口,像“替身演员”只模仿有剧本(接口)的角色
  • CGLIB:直接给类生成子类,像“整容”一样连没接口的类也能代理(Spring 默认选它)
项目JDK 动态代理CGLIB(Code Generation Library)2025 年谁更常用?
能不能代理的类必须实现接口接口、普通类、final 类都不行CGLIB 完胜
底层实现java.lang.reflect.ProxyASM 字节码操作(生成子类)——
代理后对象类型实现原接口继承原类(是原类的子类)——
能不能代理 private/final 方法不能(只能 public)不能 final 方法,但能 private(实际很少用)——
性能稍快(反射调用)更快(直接子类方法调用)CGLIB 更快
Spring 默认用谁有接口 → 用 JDK无接口 或 强制用 → 用 CGLIBCGLIB
Spring Boot 3.x 默认直接默认 CGLIB(连有接口也用 CGLIB)——CGLIB 统治世界

Spring 到底什么时候用哪一个?(2025 真实规则)

情况Spring 用谁?说明
被代理的类实现了接口(传统写法)默认用 JDK 动态代理Spring 5 以前的默认行为
被代理的类没有实现任何接口强制用 CGLIB必须用子类方式
加了 @Transactional 的类有接口Spring Boot 3 默认 CGLIB强制用 CGLIB(推荐)
被代理的类是 final报错!两个都不能代理final 类无法继承,final 方法无法覆盖
方法是 final / static / privateAOP 不生效两个代理都只能代理 public 非 final 方法

Spring Boot 3(Spring 6)已经彻底抛弃 JDK 代理了!

从 Spring Boot 3.0 开始:

# application.yml 一行配置就能全局强制用 CGLIB(默认就是 true)
spring:
  aop:
    proxy-target-class: true   # 默认就是 true!强制 CGLIB

也就是说:2025 年你写 @Transactional、@Cacheable、自定义切面,99.99% 都是 CGLIB 在干活!

经典面试题 + 标准答案(直接背)

  1. Spring AOP 默认用 JDK 还是 CGLIB?
    答:Spring Boot 3.x 默认强制 CGLIB(proxy-target-class=true),即使有接口也用 CGLIB。
  2. 为什么 Spring Boot 3 要强制用 CGLIB?
    答:
  • 避免“接口多了不知道用哪个”的歧义
  • CGLIB 性能更好(直接子类调用 > 接口反射)
  • 支持记录真实类名(日志里显示 UserService 而不是 UserService$$EnhancerBySpringCGLIB)
  1. final 类能被代理吗?
    答:不能!CGLIB 需要生成子类,final 类禁止继承,直接报错。
  2. 同一个类里 this.method() 调用,AOP 会生效吗?
    答:不会!因为没走代理。
    解决办法:
  • 用 @Autowired 把自己注入自己
  • 用 AopContext.currentProxy()
  • 或者直接别在内部调用,暴露一个 Service 方法给外部调
  1. 怎么看一个对象是不是代理对象?
    答:
  • 看类名:UserService$$EnhancerBySpringCGLIB$$ 开头就是 CGLIB
  • 代码里打印:System.out.println(userService.getClass().getName());
  1. JDK 动态代理和 CGLIB 性能差距大吗?
    答:现代 JVM 下差距很小,但 CGLIB 还是更快一点。Spring Boot 3 直接选 CGLIB 就是为了性能+一致性。

终极记忆口诀(10 秒背会)

“有接口曾经用 JDK,Boot 3 之后全 CGLIB
final 类来直接死,内部调用不生效
日志看类带 Enhancer,CGLIB 在背后使劲!”

面试画图神器(30 秒画完)

JDK 动态代理                 CGLIB(2025 主流)
┌─────────────┐             ┌─────────────┐
│ Proxy$1     │◄─────接口──│ 子类        │
└─────────────┘             └─────────────┘
      ▲                            ▲
      └─────────实现───────────────┘
           Target(原类)

背完这张表 + 口诀 + 6 个答案,
面试官问“Spring 动态代理和 CGLIB 区别”,你 1 分钟画图 + 甩代码 + 说 Boot 3 默认 CGLIB,
他直接在简历写“Spring AOP 原理极扎实”!
现在你已经彻底搞懂 Spring 底层代理了,大厂随便进!冲!

文章已创建 3958

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部